Repository: UmbrellaDocs/linkspector
Pull request #106 (2025-03-18 13:13:05)

Feat: Add statistics display for link checks
## Description

Backend work for https://github.com/UmbrellaDocs/action-linkspector/issues/36
- Fixed `npm` dependencies.

## Type of Change

Please delete options that are not relevant.

- [x] New feature (non-breaking change which adds functionality)
- [x] This change requires a documentation update

## Checklist:

- [x] I have performed a self-review of my own code
- [x] I have commented my code, particularly in hard-to-understand areas
- [x] I have made corresponding changes to the documentation
- [x] My changes generate no new warnings
- [x] I have added tests that prove my fix is effective or that my feature works
- [x] New and existing unit tests pass locally with my changes



Patch:
diff --git a/README.md b/README.md
index a379dd8..e397a32 100644
--- a/README.md
+++ b/README.md
@@ -71,6 +71,15 @@ To check hyperlinks in your markup language files, follow these steps:
 
 1. After the check is complete, Linkspector provides a summary of the results. If any dead links are found, they are listed in the terminal, along with their status codes and error messages.
 
+   - To display statistics about the checked links, use the `-s` or `--showstat` option:
+
+     ```bash
+     linkspector check -s
+     ```
+
+     This command shows a summary table with the number of files checked, total links, hyperlinks, file and header links, and the count of correct and failed links.
+     Note that this option cannot be used together with the JSON output option (`-j`).
+
 1. If no dead links are found, Linkspector displays a success message, indicating that all links are working.
 
 ## Configuration
diff --git a/index.js b/index.js
index f39e459..ae829aa 100755
--- a/index.js
+++ b/index.js
@@ -15,12 +15,34 @@ program
   .description('Check hyperlinks based on the configuration file.')
   .option('-c, --config <path>', 'Specify a custom configuration file path')
   .option('-j, --json', 'Output the results in JSON format')
+  .option('-s, --showstat', 'Display statistics about the links checked')
   .action(async (cmd) => {
+    // Validate that -j and -s options are not used together
+    if (cmd.json && cmd.showstat) {
+      console.error(
+        kleur.red(
+          'Error: The --json and --showstat options cannot be used together.'
+        )
+      )
+      process.exit(1)
+    }
+
     const configFile = cmd.config || '.linkspector.yml' // Use custom config file path if provided
 
     let currentFile = '' // Variable to store the current file name
     let results = [] // Array to store the results if json is true
 
+    // Initialize statistics counters
+    let stats = {
+      filesChecked: 0,
+      totalLinks: 0,
+      httpLinks: 0,
+      fileLinks: 0,
+      emailLinks: 0,
+      correctLinks: 0,
+      failedLinks: 0,
+    }
+
     const spinner = cmd.json ? null : ora().start()
 
     try {
@@ -42,8 +64,36 @@ program
           spinner.text = `Checking ${currentFile}...\n`
         }
 
+        // Increment file count for statistics
+        stats.filesChecked++
+
         for (const linkStatusObj of result) {
+          // Count total links
+          stats.totalLinks++
+
+          // Count links by type
+          if (linkStatusObj.link && linkStatusObj.link.match(/^https?:\/\//)) {
+            stats.httpLinks++
+          } else if (
+            linkStatusObj.link &&
+            linkStatusObj.link.startsWith('mailto:')
+          ) {
+            stats.emailLinks++
+          } else if (
+            linkStatusObj.link &&
+            (linkStatusObj.link.startsWith('#') ||
+              linkStatusObj.link.includes('.md') ||
+              linkStatusObj.link.includes('#'))
+          ) {
+            stats.fileLinks++
+          } else if (linkStatusObj.link) {
+            // Count any remaining links as file links
+            stats.fileLinks++
+          }
+
+          // Count correct vs failed links - Updated to handle skipped links
           if (linkStatusObj.status === 'error') {
+            stats.failedLinks++
             if (cmd.json) {
               results.diagnostics.push({
                 message: `Cannot reach ${linkStatusObj.link}. Status: ${linkStatusObj.status_code}${linkStatusObj.error_message ? ` ${linkStatusObj.error_message}` : ''}`,
@@ -73,6 +123,16 @@ program
               spinner.start(`Checking ${currentFile}...\n`)
             }
             hasErrorLinks = true
+          } else if (
+            linkStatusObj.status === 'alive' ||
+            linkStatusObj.status === 'assumed alive'
+          ) {
+            stats.correctLinks++
+          } else if (linkStatusObj.status === 'skipped') {
+            // Skipped links don't count towards failed links
+          } else {
+            // Count other status as failed
+            stats.failedLinks++
           }
         }
       }
@@ -86,8 +146,44 @@ program
         }
       }
 
+      // Display statistics if --showstat option is used
+      if (cmd.showstat) {
+        spinner.stop()
+        console.log('\n' + kleur.bold('💀📊 Linkspector check stats'))
+        console.log('┌───────────────────────────────┬────────┐')
+        console.log(
+          `│ 🟰 ${kleur.bold('Total files checked')}        │ ${kleur.cyan(padNumber(stats.filesChecked))} │`
+        )
+        console.log('├───────────────────────────────┼────────┤')
+        console.log(
+          `│ 🔗 ${kleur.bold('Total links checked')}        │ ${kleur.cyan(padNumber(stats.totalLinks))} │`
+        )
+        console.log('├───────────────────────────────┼────────┤')
+        console.log(
+          `│ 🌐 ${kleur.bold('Hyperlinks')}                 │ ${kleur.cyan(padNumber(stats.httpLinks))} │`
+        )
+        console.log('├───────────────────────────────┼────────┤')
+        console.log(
+          `│ 📁 ${kleur.bold('File and header links')}      │ ${kleur.cyan(padNumber(stats.fileLinks))} │`
+        )
+        console.log('├───────────────────────────────┼────────┤')
+        console.log(
+          `│ ✉️  ${kleur.bold('Email links (Skipped)')}      │ ${kleur.cyan(padNumber(stats.emailLinks))} │`
+        )
+        console.log('├───────────────────────────────┼────────┤')
+        console.log(
+          `│ ✅ ${kleur.bold('Working links')}              │ ${kleur.green(padNumber(stats.correctLinks))} │`
+        )
+        console.log('├───────────────────────────────┼────────┤')
+        console.log(
+          `│ 🚫 ${kleur.bold('Failed links')}               │ ${kleur.red(padNumber(stats.failedLinks))} │`
+        )
+        console.log('└───────────────────────────────┴────────┘')
+        console.log('')
+      }
+
       if (!hasErrorLinks) {
-        if (!cmd.json) {
+        if (!cmd.json && !cmd.showstat) {
           spinner.stop()
           console.log(
             kleur.green(
@@ -97,20 +193,32 @@ program
         }
         process.exit(0)
       } else {
-        if (!cmd.json) {
+        if (!cmd.json && !cmd.showstat) {
           spinner.stop()
           console.error(
             kleur.red(
               '💥 Error: Some hyperlinks in the specified files are invalid.'
             )
           )
+        } else if (cmd.showstat) {
+          console.error(
+            kleur.red(
+              '💥 Error: Some hyperlinks in the specified files are invalid.'
+            )
+          )
         }
         process.exit(1)
       }
     } catch (error) {
+      if (spinner) spinner.stop()
       console.error(kleur.red(`💥 Main error: ${error.message}`))
       process.exit(1)
     }
+
+    // Helper function to pad numbers for consistent table formatting
+    function padNumber(num) {
+      return num.toString().padStart(6, ' ')
+    }
   })
 
 // Parse the command line arguments
diff --git a/lib/update-linkstatus-obj.js b/lib/update-linkstatus-obj.js
index 3443ccb..ab27f0c 100644
--- a/lib/update-linkstatus-obj.js
+++ b/lib/update-linkstatus-obj.js
@@ -46,13 +46,24 @@ function updateLinkStatusObj(astNodes, linkStatus) {
         })
       }
     } else {
+      let status = null
+      let statusCode = null
+      let errorMessage = null
+
+      // Special handling for mailto links
+      if (node.url && node.url.startsWith('mailto:')) {
+        status = 'skipped'
+        statusCode = 200
+        errorMessage = 'Email links are not checked'
+      }
+
       updatedLinkStatus.push({
         link: node.url,
-        status: null,
-        status_code: null,
-        line_number: null,
+        status: status,
+        status_code: statusCode,
+        line_number: node.position ? node.position.start.line : null,
         position: node.position,
-        error_message: null,
+        error_message: errorMessage,
         title: node.title,
         children: node.children,
       })
diff --git a/package-lock.json b/package-lock.json
index 7ae5ae7..a107200 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -16,9 +16,9 @@
         "joi": "^17.13.3",
         "js-yaml": "^4.1.0",
         "kleur": "^4.1.5",
-        "ora": "^8.1.1",
-        "puppeteer": "^24.1.1",
-        "remark-gfm": "^4.0.0",
+        "ora": "^8.2.0",
+        "puppeteer": "^24.4.0",
+        "remark-gfm": "^4.0.1",
         "remark-parse": "^11.0.0",
         "unified": "^11.0.5",
         "unist-util-visit": "^5.0.0"
@@ -27,7 +27,7 @@
         "linkspector": "index.js"
       },
       "devDependencies": {
-        "vitest": "^3.0.4"
+        "vitest": "^3.0.9"
       }
     },
     "node_modules/@babel/code-frame": {
@@ -97,9 +97,9 @@
       }
     },
     "node_modules/@esbuild/aix-ppc64": {
-      "version": "0.24.2",
-      "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.24.2.tgz",
-      "integrity": "sha512-thpVCb/rhxE/BnMLQ7GReQLLN8q9qbHmI55F4489/ByVg2aQaQ6kbcLb6FHkocZzQhxc4gx0sCk0tJkKBFzDhA==",
+      "version": "0.25.1",
+      "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.25.1.tgz",
+      "integrity": "sha512-kfYGy8IdzTGy+z0vFGvExZtxkFlA4zAxgKEahG9KE1ScBjpQnFsNOX8KTU5ojNru5ed5CVoJYXFtoxaq5nFbjQ==",
       "cpu": [
         "ppc64"
       ],
@@ -114,9 +114,9 @@
       }
     },
     "node_modules/@esbuild/android-arm": {
-      "version": "0.24.2",
-      "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.24.2.tgz",
-      "integrity": "sha512-tmwl4hJkCfNHwFB3nBa8z1Uy3ypZpxqxfTQOcHX+xRByyYgunVbZ9MzUUfb0RxaHIMnbHagwAxuTL+tnNM+1/Q==",
+      "version": "0.25.1",
+      "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.25.1.tgz",
+      "integrity": "sha512-dp+MshLYux6j/JjdqVLnMglQlFu+MuVeNrmT5nk6q07wNhCdSnB7QZj+7G8VMUGh1q+vj2Bq8kRsuyA00I/k+Q==",
       "cpu": [
         "arm"
       ],
@@ -131,9 +131,9 @@
       }
     },
     "node_modules/@esbuild/android-arm64": {
-      "version": "0.24.2",
-      "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.24.2.tgz",
-      "integrity": "sha512-cNLgeqCqV8WxfcTIOeL4OAtSmL8JjcN6m09XIgro1Wi7cF4t/THaWEa7eL5CMoMBdjoHOTh/vwTO/o2TRXIyzg==",
+      "version": "0.25.1",
+      "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.25.1.tgz",
+      "integrity": "sha512-50tM0zCJW5kGqgG7fQ7IHvQOcAn9TKiVRuQ/lN0xR+T2lzEFvAi1ZcS8DiksFcEpf1t/GYOeOfCAgDHFpkiSmA==",
       "cpu": [
         "arm64"
       ],
@@ -148,9 +148,9 @@
       }
     },
     "node_modules/@esbuild/android-x64": {
-      "version": "0.24.2",
-      "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.24.2.tgz",
-      "integrity": "sha512-B6Q0YQDqMx9D7rvIcsXfmJfvUYLoP722bgfBlO5cGvNVb5V/+Y7nhBE3mHV9OpxBf4eAS2S68KZztiPaWq4XYw==",
+      "version": "0.25.1",
+      "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.25.1.tgz",
+      "integrity": "sha512-GCj6WfUtNldqUzYkN/ITtlhwQqGWu9S45vUXs7EIYf+7rCiiqH9bCloatO9VhxsL0Pji+PF4Lz2XXCES+Q8hDw==",
       "cpu": [
         "x64"
       ],
@@ -165,9 +165,9 @@
       }
     },
     "node_modules/@esbuild/darwin-arm64": {
-      "version": "0.24.2",
-      "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.24.2.tgz",
-      "integrity": "sha512-kj3AnYWc+CekmZnS5IPu9D+HWtUI49hbnyqk0FLEJDbzCIQt7hg7ucF1SQAilhtYpIujfaHr6O0UHlzzSPdOeA==",
+      "version": "0.25.1",
+      "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.25.1.tgz",
+      "integrity": "sha512-5hEZKPf+nQjYoSr/elb62U19/l1mZDdqidGfmFutVUjjUZrOazAtwK+Kr+3y0C/oeJfLlxo9fXb1w7L+P7E4FQ==",
       "cpu": [
         "arm64"
       ],
@@ -182,9 +182,9 @@
       }
     },
     "node_modules/@esbuild/darwin-x64": {
-      "version": "0.24.2",
-      "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.24.2.tgz",
-      "integrity": "sha512-WeSrmwwHaPkNR5H3yYfowhZcbriGqooyu3zI/3GGpF8AyUdsrrP0X6KumITGA9WOyiJavnGZUwPGvxvwfWPHIA==",
+      "version": "0.25.1",
+      "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.25.1.tgz",
+      "integrity": "sha512-hxVnwL2Dqs3fM1IWq8Iezh0cX7ZGdVhbTfnOy5uURtao5OIVCEyj9xIzemDi7sRvKsuSdtCAhMKarxqtlyVyfA==",
       "cpu": [
         "x64"
       ],
@@ -199,9 +199,9 @@
       }
     },
     "node_modules/@esbuild/freebsd-arm64": {
-      "version": "0.24.2",
-      "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.24.2.tgz",
-      "integrity": "sha512-UN8HXjtJ0k/Mj6a9+5u6+2eZ2ERD7Edt1Q9IZiB5UZAIdPnVKDoG7mdTVGhHJIeEml60JteamR3qhsr1r8gXvg==",
+      "version": "0.25.1",
+      "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.25.1.tgz",
+      "integrity": "sha512-1MrCZs0fZa2g8E+FUo2ipw6jw5qqQiH+tERoS5fAfKnRx6NXH31tXBKI3VpmLijLH6yriMZsxJtaXUyFt/8Y4A==",
       "cpu": [
         "arm64"
       ],
@@ -216,9 +216,9 @@
       }
     },
     "node_modules/@esbuild/freebsd-x64": {
-      "version": "0.24.2",
-      "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.24.2.tgz",
-      "integrity": "sha512-TvW7wE/89PYW+IevEJXZ5sF6gJRDY/14hyIGFXdIucxCsbRmLUcjseQu1SyTko+2idmCw94TgyaEZi9HUSOe3Q==",
+      "version": "0.25.1",
+      "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.25.1.tgz",
+      "integrity": "sha512-0IZWLiTyz7nm0xuIs0q1Y3QWJC52R8aSXxe40VUxm6BB1RNmkODtW6LHvWRrGiICulcX7ZvyH6h5fqdLu4gkww==",
       "cpu": [
         "x64"
       ],
@@ -233,9 +233,9 @@
       }
     },
     "node_modules/@esbuild/linux-arm": {
-      "version": "0.24.2",
-      "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.24.2.tgz",
-      "integrity": "sha512-n0WRM/gWIdU29J57hJyUdIsk0WarGd6To0s+Y+LwvlC55wt+GT/OgkwoXCXvIue1i1sSNWblHEig00GBWiJgfA==",
+      "version": "0.25.1",
+      "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.25.1.tgz",
+      "integrity": "sha512-NdKOhS4u7JhDKw9G3cY6sWqFcnLITn6SqivVArbzIaf3cemShqfLGHYMx8Xlm/lBit3/5d7kXvriTUGa5YViuQ==",
       "cpu": [
         "arm"
       ],
@@ -250,9 +250,9 @@
       }
     },
     "node_modules/@esbuild/linux-arm64": {
-      "version": "0.24.2",
-      "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.24.2.tgz",
-      "integrity": "sha512-7HnAD6074BW43YvvUmE/35Id9/NB7BeX5EoNkK9obndmZBUk8xmJJeU7DwmUeN7tkysslb2eSl6CTrYz6oEMQg==",
+      "version": "0.25.1",
+      "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.25.1.tgz",
+      "integrity": "sha512-jaN3dHi0/DDPelk0nLcXRm1q7DNJpjXy7yWaWvbfkPvI+7XNSc/lDOnCLN7gzsyzgu6qSAmgSvP9oXAhP973uQ==",
       "cpu": [
         "arm64"
       ],
@@ -267,9 +267,9 @@
       }
     },
     "node_modules/@esbuild/linux-ia32": {
-      "version": "0.24.2",
-      "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.24.2.tgz",
-      "integrity": "sha512-sfv0tGPQhcZOgTKO3oBE9xpHuUqguHvSo4jl+wjnKwFpapx+vUDcawbwPNuBIAYdRAvIDBfZVvXprIj3HA+Ugw==",
+      "version": "0.25.1",
+      "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.25.1.tgz",
+      "integrity": "sha512-OJykPaF4v8JidKNGz8c/q1lBO44sQNUQtq1KktJXdBLn1hPod5rE/Hko5ugKKZd+D2+o1a9MFGUEIUwO2YfgkQ==",
       "cpu": [
         "ia32"
       ],
@@ -284,9 +284,9 @@
       }
     },
     "node_modules/@esbuild/linux-loong64": {
-      "version": "0.24.2",
-      "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.24.2.tgz",
-      "integrity": "sha512-CN9AZr8kEndGooS35ntToZLTQLHEjtVB5n7dl8ZcTZMonJ7CCfStrYhrzF97eAecqVbVJ7APOEe18RPI4KLhwQ==",
+      "version": "0.25.1",
+      "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.25.1.tgz",
+      "integrity": "sha512-nGfornQj4dzcq5Vp835oM/o21UMlXzn79KobKlcs3Wz9smwiifknLy4xDCLUU0BWp7b/houtdrgUz7nOGnfIYg==",
       "cpu": [
         "loong64"
       ],
@@ -301,9 +301,9 @@
       }
     },
     "node_modules/@esbuild/linux-mips64el": {
-      "version": "0.24.2",
-      "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.24.2.tgz",
-      "integrity": "sha512-iMkk7qr/wl3exJATwkISxI7kTcmHKE+BlymIAbHO8xanq/TjHaaVThFF6ipWzPHryoFsesNQJPE/3wFJw4+huw==",
+      "version": "0.25.1",
+      "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.25.1.tgz",
+      "integrity": "sha512-1osBbPEFYwIE5IVB/0g2X6i1qInZa1aIoj1TdL4AaAb55xIIgbg8Doq6a5BzYWgr+tEcDzYH67XVnTmUzL+nXg==",
       "cpu": [
         "mips64el"
       ],
@@ -318,9 +318,9 @@
       }
     },
     "node_modules/@esbuild/linux-ppc64": {
-      "version": "0.24.2",
-      "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.24.2.tgz",
-      "integrity": "sha512-shsVrgCZ57Vr2L8mm39kO5PPIb+843FStGt7sGGoqiiWYconSxwTiuswC1VJZLCjNiMLAMh34jg4VSEQb+iEbw==",
+      "version": "0.25.1",
+      "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.25.1.tgz",
+      "integrity": "sha512-/6VBJOwUf3TdTvJZ82qF3tbLuWsscd7/1w+D9LH0W/SqUgM5/JJD0lrJ1fVIfZsqB6RFmLCe0Xz3fmZc3WtyVg==",
       "cpu": [
         "ppc64"
       ],
@@ -335,9 +335,9 @@
       }
     },
     "node_modules/@esbuild/linux-riscv64": {
-      "version": "0.24.2",
-      "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.24.2.tgz",
-      "integrity": "sha512-4eSFWnU9Hhd68fW16GD0TINewo1L6dRrB+oLNNbYyMUAeOD2yCK5KXGK1GH4qD/kT+bTEXjsyTCiJGHPZ3eM9Q==",
+      "version": "0.25.1",
+      "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.25.1.tgz",
+      "integrity": "sha512-nSut/Mx5gnilhcq2yIMLMe3Wl4FK5wx/o0QuuCLMtmJn+WeWYoEGDN1ipcN72g1WHsnIbxGXd4i/MF0gTcuAjQ==",
       "cpu": [
         "riscv64"
       ],
@@ -352,9 +352,9 @@
       }
     },
     "node_modules/@esbuild/linux-s390x": {
-      "version": "0.24.2",
-      "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.24.2.tgz",
-      "integrity": "sha512-S0Bh0A53b0YHL2XEXC20bHLuGMOhFDO6GN4b3YjRLK//Ep3ql3erpNcPlEFed93hsQAjAQDNsvcK+hV90FubSw==",
+      "version": "0.25.1",
+      "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.25.1.tgz",
+      "integrity": "sha512-cEECeLlJNfT8kZHqLarDBQso9a27o2Zd2AQ8USAEoGtejOrCYHNtKP8XQhMDJMtthdF4GBmjR2au3x1udADQQQ==",
       "cpu": [
         "s390x"
       ],
@@ -369,9 +369,9 @@
       }
     },
     "node_modules/@esbuild/linux-x64": {
-      "version": "0.24.2",
-      "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.24.2.tgz",
-      "integrity": "sha512-8Qi4nQcCTbLnK9WoMjdC9NiTG6/E38RNICU6sUNqK0QFxCYgoARqVqxdFmWkdonVsvGqWhmm7MO0jyTqLqwj0Q==",
+      "version": "0.25.1",
+      "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.25.1.tgz",
+      "integrity": "sha512-xbfUhu/gnvSEg+EGovRc+kjBAkrvtk38RlerAzQxvMzlB4fXpCFCeUAYzJvrnhFtdeyVCDANSjJvOvGYoeKzFA==",
       "cpu": [
         "x64"
       ],
@@ -386,9 +386,9 @@
       }
     },
     "node_modules/@esbuild/netbsd-arm64": {
-      "version": "0.24.2",
-      "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.24.2.tgz",
-      "integrity": "sha512-wuLK/VztRRpMt9zyHSazyCVdCXlpHkKm34WUyinD2lzK07FAHTq0KQvZZlXikNWkDGoT6x3TD51jKQ7gMVpopw==",
+      "version": "0.25.1",
+      "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.25.1.tgz",
+      "integrity": "sha512-O96poM2XGhLtpTh+s4+nP7YCCAfb4tJNRVZHfIE7dgmax+yMP2WgMd2OecBuaATHKTHsLWHQeuaxMRnCsH8+5g==",
       "cpu": [
         "arm64"
       ],
@@ -403,9 +403,9 @@
       }
     },
     "node_modules/@esbuild/netbsd-x64": {
-      "version": "0.24.2",
-      "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.24.2.tgz",
-      "integrity": "sha512-VefFaQUc4FMmJuAxmIHgUmfNiLXY438XrL4GDNV1Y1H/RW3qow68xTwjZKfj/+Plp9NANmzbH5R40Meudu8mmw==",
+      "version": "0.25.1",
+      "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.25.1.tgz",
+      "integrity": "sha512-X53z6uXip6KFXBQ+Krbx25XHV/NCbzryM6ehOAeAil7X7oa4XIq+394PWGnwaSQ2WRA0KI6PUO6hTO5zeF5ijA==",
       "cpu": [
         "x64"
       ],
@@ -420,9 +420,9 @@
       }
     },
     "node_modules/@esbuild/openbsd-arm64": {
-      "version": "0.24.2",
-      "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.24.2.tgz",
-      "integrity": "sha512-YQbi46SBct6iKnszhSvdluqDmxCJA+Pu280Av9WICNwQmMxV7nLRHZfjQzwbPs3jeWnuAhE9Jy0NrnJ12Oz+0A==",
+      "version": "0.25.1",
+      "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.25.1.tgz",
+      "integrity": "sha512-Na9T3szbXezdzM/Kfs3GcRQNjHzM6GzFBeU1/6IV/npKP5ORtp9zbQjvkDJ47s6BCgaAZnnnu/cY1x342+MvZg==",
       "cpu": [
         "arm64"
       ],
@@ -437,9 +437,9 @@
       }
     },
     "node_modules/@esbuild/openbsd-x64": {
-      "version": "0.24.2",
-      "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.24.2.tgz",
-      "integrity": "sha512-+iDS6zpNM6EnJyWv0bMGLWSWeXGN/HTaF/LXHXHwejGsVi+ooqDfMCCTerNFxEkM3wYVcExkeGXNqshc9iMaOA==",
+      "version": "0.25.1",
+      "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.25.1.tgz",
+      "integrity": "sha512-T3H78X2h1tszfRSf+txbt5aOp/e7TAz3ptVKu9Oyir3IAOFPGV6O9c2naym5TOriy1l0nNf6a4X5UXRZSGX/dw==",
       "cpu": [
         "x64"
       ],
@@ -454,9 +454,9 @@
       }
     },
     "node_modules/@esbuild/sunos-x64": {
-      "version": "0.24.2",
-      "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.24.2.tgz",
-      "integrity": "sha512-hTdsW27jcktEvpwNHJU4ZwWFGkz2zRJUz8pvddmXPtXDzVKTTINmlmga3ZzwcuMpUvLw7JkLy9QLKyGpD2Yxig==",
+      "version": "0.25.1",
+      "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.25.1.tgz",
+      "integrity": "sha512-2H3RUvcmULO7dIE5EWJH8eubZAI4xw54H1ilJnRNZdeo8dTADEZ21w6J22XBkXqGJbe0+wnNJtw3UXRoLJnFEg==",
       "cpu": [
         "x64"
       ],
@@ -471,9 +471,9 @@
       }
     },
     "node_modules/@esbuild/win32-arm64": {
-      "version": "0.24.2",
-      "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.24.2.tgz",
-      "integrity": "sha512-LihEQ2BBKVFLOC9ZItT9iFprsE9tqjDjnbulhHoFxYQtQfai7qfluVODIYxt1PgdoyQkz23+01rzwNwYfutxUQ==",
+      "version": "0.25.1",
+      "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.25.1.tgz",
+      "integrity": "sha512-GE7XvrdOzrb+yVKB9KsRMq+7a2U/K5Cf/8grVFRAGJmfADr/e/ODQ134RK2/eeHqYV5eQRFxb1hY7Nr15fv1NQ==",
       "cpu": [
         "arm64"
       ],
@@ -488,9 +488,9 @@
       }
     },
     "node_modules/@esbuild/win32-ia32": {
-      "version": "0.24.2",
-      "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.24.2.tgz",
-      "integrity": "sha512-q+iGUwfs8tncmFC9pcnD5IvRHAzmbwQ3GPS5/ceCyHdjXubwQWI12MKWSNSMYLJMq23/IUCvJMS76PDqXe1fxA==",
+      "version": "0.25.1",
+      "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.25.1.tgz",
+      "integrity": "sha512-uOxSJCIcavSiT6UnBhBzE8wy3n0hOkJsBOzy7HDAuTDE++1DJMRRVCPGisULScHL+a/ZwdXPpXD3IyFKjA7K8A==",
       "cpu": [
         "ia32"
       ],
@@ -505,9 +505,9 @@
       }
     },
     "node_modules/@esbuild/win32-x64": {
-      "version": "0.24.2",
-      "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.24.2.tgz",
-      "integrity": "sha512-7VTgWzgMGvup6aSqDPLiW5zHaxYJGTO4OokMjIlrCtf+VpEL+cXKtCvg723iguPYI5oaUNdS+/V7OU2gvXVWEg==",
+      "version": "0.25.1",
+      "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.25.1.tgz",
+      "integrity": "sha512-Y1EQdcfwMSeQN/ujR5VayLOJ1BHaK+ssyk0AEzPjC+t1lITgsnccPqFjb6V+LsTp/9Iov4ysfjxLaGJ9RPtkVg==",
       "cpu": [
         "x64"
       ],
@@ -569,18 +569,17 @@
       }
     },
     "node_modules/@puppeteer/browsers": {
-      "version": "2.7.0",
-      "resolved": "https://registry.npmjs.org/@puppeteer/browsers/-/browsers-2.7.0.tgz",
-      "integrity": "sha512-bO61XnTuopsz9kvtfqhVbH6LTM1koxK0IlBR+yuVrM2LB7mk8+5o1w18l5zqd5cs8xlf+ntgambqRqGifMDjog==",
+      "version": "2.8.0",
+      "resolved": "https://registry.npmjs.org/@puppeteer/browsers/-/browsers-2.8.0.tgz",
+      "integrity": "sha512-yTwt2KWRmCQAfhvbCRjebaSX8pV1//I0Y3g+A7f/eS7gf0l4eRJoUCvcYdVtboeU4CTOZQuqYbZNS8aBYb8ROQ==",
       "license": "Apache-2.0",
       "dependencies": {
         "debug": "^4.4.0",
         "extract-zip": "^2.0.1",
         "progress": "^2.0.3",
         "proxy-agent": "^6.5.0",
-        "semver": "^7.6.3",
-        "tar-fs": "^3.0.6",
-        "unbzip2-stream": "^1.4.3",
+        "semver": "^7.7.1",
+        "tar-fs": "^3.0.8",
         "yargs": "^17.7.2"
       },
       "bin": {
@@ -591,9 +590,9 @@
       }
     },
     "node_modules/@rollup/rollup-android-arm-eabi": {
-      "version": "4.32.1",
-      "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.32.1.tgz",
-      "integrity": "sha512-/pqA4DmqyCm8u5YIDzIdlLcEmuvxb0v8fZdFhVMszSpDTgbQKdw3/mB3eMUHIbubtJ6F9j+LtmyCnHTEqIHyzA==",
+      "version": "4.36.0",
+      "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.36.0.tgz",
+      "integrity": "sha512-jgrXjjcEwN6XpZXL0HUeOVGfjXhPyxAbbhD0BlXUB+abTOpbPiN5Wb3kOT7yb+uEtATNYF5x5gIfwutmuBA26w==",
       "cpu": [
         "arm"
       ],
@@ -605,9 +604,9 @@
       ]
     },
     "node_modules/@rollup/rollup-android-arm64": {
-      "version": "4.32.1",
-      "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.32.1.tgz",
-      "integrity": "sha512-If3PDskT77q7zgqVqYuj7WG3WC08G1kwXGVFi9Jr8nY6eHucREHkfpX79c0ACAjLj3QIWKPJR7w4i+f5EdLH5Q==",
+      "version": "4.36.0",
+      "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.36.0.tgz",
+      "integrity": "sha512-NyfuLvdPdNUfUNeYKUwPwKsE5SXa2J6bCt2LdB/N+AxShnkpiczi3tcLJrm5mA+eqpy0HmaIY9F6XCa32N5yzg==",
       "cpu": [
         "arm64"
       ],
@@ -619,9 +618,9 @@
       ]
     },
     "node_modules/@rollup/rollup-darwin-arm64": {
-      "version": "4.32.1",
-      "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.32.1.tgz",
-      "integrity": "sha512-zCpKHioQ9KgZToFp5Wvz6zaWbMzYQ2LJHQ+QixDKq52KKrF65ueu6Af4hLlLWHjX1Wf/0G5kSJM9PySW9IrvHA==",
+      "version": "4.36.0",
+      "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.36.0.tgz",
+      "integrity": "sha512-JQ1Jk5G4bGrD4pWJQzWsD8I1n1mgPXq33+/vP4sk8j/z/C2siRuxZtaUA7yMTf71TCZTZl/4e1bfzwUmFb3+rw==",
       "cpu": [
         "arm64"
       ],
@@ -633,9 +632,9 @@
       ]
     },
     "node_modules/@rollup/rollup-darwin-x64": {
-      "version": "4.32.1",
-      "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.32.1.tgz",
-      "integrity": "sha512-sFvF+t2+TyUo/ZQqUcifrJIgznx58oFZbdHS9TvHq3xhPVL9nOp+yZ6LKrO9GWTP+6DbFtoyLDbjTpR62Mbr3Q==",
+      "version": "4.36.0",
+      "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.36.0.tgz",
+      "integrity": "sha512-6c6wMZa1lrtiRsbDziCmjE53YbTkxMYhhnWnSW8R/yqsM7a6mSJ3uAVT0t8Y/DGt7gxUWYuFM4bwWk9XCJrFKA==",
       "cpu": [
         "x64"
       ],
@@ -647,9 +646,9 @@
       ]
     },
     "node_modules/@rollup/rollup-freebsd-arm64": {
-      "version": "4.32.1",
-      "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.32.1.tgz",
-      "integrity": "sha512-NbOa+7InvMWRcY9RG+B6kKIMD/FsnQPH0MWUvDlQB1iXnF/UcKSudCXZtv4lW+C276g3w5AxPbfry5rSYvyeYA==",
+      "version": "4.36.0",
+      "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.36.0.tgz",
+      "integrity": "sha512-KXVsijKeJXOl8QzXTsA+sHVDsFOmMCdBRgFmBb+mfEb/7geR7+C8ypAml4fquUt14ZyVXaw2o1FWhqAfOvA4sg==",
       "cpu": [
         "arm64"
       ],
@@ -661,9 +660,9 @@
       ]
     },
     "node_modules/@rollup/rollup-freebsd-x64": {
-      "version": "4.32.1",
-      "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.32.1.tgz",
-      "integrity": "sha512-JRBRmwvHPXR881j2xjry8HZ86wIPK2CcDw0EXchE1UgU0ubWp9nvlT7cZYKc6bkypBt745b4bglf3+xJ7hXWWw==",
+      "version": "4.36.0",
+      "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.36.0.tgz",
+      "integrity": "sha512-dVeWq1ebbvByI+ndz4IJcD4a09RJgRYmLccwlQ8bPd4olz3Y213uf1iwvc7ZaxNn2ab7bjc08PrtBgMu6nb4pQ==",
       "cpu": [
         "x64"
       ],
@@ -675,9 +674,9 @@
       ]
     },
     "node_modules/@rollup/rollup-linux-arm-gnueabihf": {
-      "version": "4.32.1",
-      "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.32.1.tgz",
-      "integrity": "sha512-PKvszb+9o/vVdUzCCjL0sKHukEQV39tD3fepXxYrHE3sTKrRdCydI7uldRLbjLmDA3TFDmh418XH19NOsDRH8g==",
+      "version": "4.36.0",
+      "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.36.0.tgz",
+      "integrity": "sha512-bvXVU42mOVcF4le6XSjscdXjqx8okv4n5vmwgzcmtvFdifQ5U4dXFYaCB87namDRKlUL9ybVtLQ9ztnawaSzvg==",
       "cpu": [
         "arm"
       ],
@@ -689,9 +688,9 @@
       ]
     },
     "node_modules/@rollup/rollup-linux-arm-musleabihf": {
-      "version": "4.32.1",
-      "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.32.1.tgz",
-      "integrity": "sha512-9WHEMV6Y89eL606ReYowXuGF1Yb2vwfKWKdD1A5h+OYnPZSJvxbEjxTRKPgi7tkP2DSnW0YLab1ooy+i/FQp/Q==",
+      "version": "4.36.0",
+      "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.36.0.tgz",
+      "integrity": "sha512-JFIQrDJYrxOnyDQGYkqnNBtjDwTgbasdbUiQvcU8JmGDfValfH1lNpng+4FWlhaVIR4KPkeddYjsVVbmJYvDcg==",
       "cpu": [
         "arm"
       ],
@@ -703,9 +702,9 @@
       ]
     },
     "node_modules/@rollup/rollup-linux-arm64-gnu": {
-      "version": "4.32.1",
-      "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.32.1.tgz",
-      "integrity": "sha512-tZWc9iEt5fGJ1CL2LRPw8OttkCBDs+D8D3oEM8mH8S1ICZCtFJhD7DZ3XMGM8kpqHvhGUTvNUYVDnmkj4BDXnw==",
+      "version": "4.36.0",
+      "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.36.0.tgz",
+      "integrity": "sha512-KqjYVh3oM1bj//5X7k79PSCZ6CvaVzb7Qs7VMWS+SlWB5M8p3FqufLP9VNp4CazJ0CsPDLwVD9r3vX7Ci4J56A==",
       "cpu": [
         "arm64"
       ],
@@ -717,9 +716,9 @@
       ]
     },
     "node_modules/@rollup/rollup-linux-arm64-musl": {
-      "version": "4.32.1",
-      "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.32.1.tgz",
-      "integrity": "sha512-FTYc2YoTWUsBz5GTTgGkRYYJ5NGJIi/rCY4oK/I8aKowx1ToXeoVVbIE4LGAjsauvlhjfl0MYacxClLld1VrOw==",
+      "version": "4.36.0",
+      "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.36.0.tgz",
+      "integrity": "sha512-QiGnhScND+mAAtfHqeT+cB1S9yFnNQ/EwCg5yE3MzoaZZnIV0RV9O5alJAoJKX/sBONVKeZdMfO8QSaWEygMhw==",
       "cpu": [
         "arm64"
       ],
@@ -731,9 +730,9 @@
       ]
     },
     "node_modules/@rollup/rollup-linux-loongarch64-gnu": {
-      "version": "4.32.1",
-      "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loongarch64-gnu/-/rollup-linux-loongarch64-gnu-4.32.1.tgz",
-      "integrity": "sha512-F51qLdOtpS6P1zJVRzYM0v6MrBNypyPEN1GfMiz0gPu9jN8ScGaEFIZQwteSsGKg799oR5EaP7+B2jHgL+d+Kw==",
+      "version": "4.36.0",
+      "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loongarch64-gnu/-/rollup-linux-loongarch64-gnu-4.36.0.tgz",
+      "integrity": "sha512-1ZPyEDWF8phd4FQtTzMh8FQwqzvIjLsl6/84gzUxnMNFBtExBtpL51H67mV9xipuxl1AEAerRBgBwFNpkw8+Lg==",
       "cpu": [
         "loong64"
       ],
@@ -745,9 +744,9 @@
       ]
     },
     "node_modules/@rollup/rollup-linux-powerpc64le-gnu": {
-      "version": "4.32.1",
-      "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-powerpc64le-gnu/-/rollup-linux-powerpc64le-gnu-4.32.1.tgz",
-      "integrity": "sha512-wO0WkfSppfX4YFm5KhdCCpnpGbtgQNj/tgvYzrVYFKDpven8w2N6Gg5nB6w+wAMO3AIfSTWeTjfVe+uZ23zAlg==",
+      "version": "4.36.0",
+      "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-powerpc64le-gnu/-/rollup-linux-powerpc64le-gnu-4.36.0.tgz",
+      "integrity": "sha512-VMPMEIUpPFKpPI9GZMhJrtu8rxnp6mJR3ZzQPykq4xc2GmdHj3Q4cA+7avMyegXy4n1v+Qynr9fR88BmyO74tg==",
       "cpu": [
         "ppc64"
       ],
@@ -759,9 +758,9 @@
       ]
     },
     "node_modules/@rollup/rollup-linux-riscv64-gnu": {
-      "version": "4.32.1",
-      "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.32.1.tgz",
-      "integrity": "sha512-iWswS9cIXfJO1MFYtI/4jjlrGb/V58oMu4dYJIKnR5UIwbkzR0PJ09O0PDZT0oJ3LYWXBSWahNf/Mjo6i1E5/g==",
+      "version": "4.36.0",
+      "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.36.0.tgz",
+      "integrity": "sha512-ttE6ayb/kHwNRJGYLpuAvB7SMtOeQnVXEIpMtAvx3kepFQeowVED0n1K9nAdraHUPJ5hydEMxBpIR7o4nrm8uA==",
       "cpu": [
         "riscv64"
       ],
@@ -773,9 +772,9 @@
       ]
     },
     "node_modules/@rollup/rollup-linux-s390x-gnu": {
-      "version": "4.32.1",
-      "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.32.1.tgz",
-      "integrity": "sha512-RKt8NI9tebzmEthMnfVgG3i/XeECkMPS+ibVZjZ6mNekpbbUmkNWuIN2yHsb/mBPyZke4nlI4YqIdFPgKuoyQQ==",
+      "version": "4.36.0",
+      "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.36.0.tgz",
+      "integrity": "sha512-4a5gf2jpS0AIe7uBjxDeUMNcFmaRTbNv7NxI5xOCs4lhzsVyGR/0qBXduPnoWf6dGC365saTiwag8hP1imTgag==",
       "cpu": [
         "s390x"
       ],
@@ -787,9 +786,9 @@
       ]
     },
     "node_modules/@rollup/rollup-linux-x64-gnu": {
-      "version": "4.32.1",
-      "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.32.1.tgz",
-      "integrity": "sha512-WQFLZ9c42ECqEjwg/GHHsouij3pzLXkFdz0UxHa/0OM12LzvX7DzedlY0SIEly2v18YZLRhCRoHZDxbBSWoGYg==",
+      "version": "4.36.0",
+      "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.36.0.tgz",
+      "integrity": "sha512-5KtoW8UWmwFKQ96aQL3LlRXX16IMwyzMq/jSSVIIyAANiE1doaQsx/KRyhAvpHlPjPiSU/AYX/8m+lQ9VToxFQ==",
       "cpu": [
         "x64"
       ],
@@ -801,9 +800,9 @@
       ]
     },
     "node_modules/@rollup/rollup-linux-x64-musl": {
-      "version": "4.32.1",
-      "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.32.1.tgz",
-      "integrity": "sha512-BLoiyHDOWoS3uccNSADMza6V6vCNiphi94tQlVIL5de+r6r/CCQuNnerf+1g2mnk2b6edp5dk0nhdZ7aEjOBsA==",
+      "version": "4.36.0",
+      "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.36.0.tgz",
+      "integrity": "sha512-sycrYZPrv2ag4OCvaN5js+f01eoZ2U+RmT5as8vhxiFz+kxwlHrsxOwKPSA8WyS+Wc6Epid9QeI/IkQ9NkgYyQ==",
       "cpu": [
         "x64"
       ],
@@ -815,9 +814,9 @@
       ]
     },
     "node_modules/@rollup/rollup-win32-arm64-msvc": {
-      "version": "4.32.1",
-      "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.32.1.tgz",
-      "integrity": "sha512-w2l3UnlgYTNNU+Z6wOR8YdaioqfEnwPjIsJ66KxKAf0p+AuL2FHeTX6qvM+p/Ue3XPBVNyVSfCrfZiQh7vZHLQ==",
+      "version": "4.36.0",
+      "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.36.0.tgz",
+      "integrity": "sha512-qbqt4N7tokFwwSVlWDsjfoHgviS3n/vZ8LK0h1uLG9TYIRuUTJC88E1xb3LM2iqZ/WTqNQjYrtmtGmrmmawB6A==",
       "cpu": [
         "arm64"
       ],
@@ -829,9 +828,9 @@
       ]
     },
     "node_modules/@rollup/rollup-win32-ia32-msvc": {
-      "version": "4.32.1",
-      "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.32.1.tgz",
-      "integrity": "sha512-Am9H+TGLomPGkBnaPWie4F3x+yQ2rr4Bk2jpwy+iV+Gel9jLAu/KqT8k3X4jxFPW6Zf8OMnehyutsd+eHoq1WQ==",
+      "version": "4.36.0",
+      "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.36.0.tgz",
+      "integrity": "sha512-t+RY0JuRamIocMuQcfwYSOkmdX9dtkr1PbhKW42AMvaDQa+jOdpUYysroTF/nuPpAaQMWp7ye+ndlmmthieJrQ==",
       "cpu": [
         "ia32"
       ],
@@ -843,9 +842,9 @@
       ]
     },
     "node_modules/@rollup/rollup-win32-x64-msvc": {
-      "version": "4.32.1",
-      "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.32.1.tgz",
-      "integrity": "sha512-ar80GhdZb4DgmW3myIS9nRFYcpJRSME8iqWgzH2i44u+IdrzmiXVxeFnExQ5v4JYUSpg94bWjevMG8JHf1Da5Q==",
+      "version": "4.36.0",
+      "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.36.0.tgz",
+      "integrity": "sha512-aRXd7tRZkWLqGbChgcMMDEHjOKudo1kChb1Jt1IfR8cY/KIpgNviLeJy5FUb9IpSuQj8dU2fAYNMPW/hLKOSTw==",
       "cpu": [
         "x64"
       ],
@@ -934,15 +933,15 @@
       }
     },
     "node_modules/@vitest/expect": {
-      "version": "3.0.4",
-      "resolved": "https://registry.npmjs.org/@vitest/expect/-/expect-3.0.4.tgz",
-      "integrity": "sha512-Nm5kJmYw6P2BxhJPkO3eKKhGYKRsnqJqf+r0yOGRKpEP+bSCBDsjXgiu1/5QFrnPMEgzfC38ZEjvCFgaNBC0Eg==",
+      "version": "3.0.9",
+      "resolved": "https://registry.npmjs.org/@vitest/expect/-/expect-3.0.9.tgz",
+      "integrity": "sha512-5eCqRItYgIML7NNVgJj6TVCmdzE7ZVgJhruW0ziSQV4V7PvLkDL1bBkBdcTs/VuIz0IxPb5da1IDSqc1TR9eig==",
       "dev": true,
       "license": "MIT",
       "dependencies": {
-        "@vitest/spy": "3.0.4",
-        "@vitest/utils": "3.0.4",
-        "chai": "^5.1.2",
+        "@vitest/spy": "3.0.9",
+        "@vitest/utils": "3.0.9",
+        "chai": "^5.2.0",
         "tinyrainbow": "^2.0.0"
       },
       "funding": {
@@ -950,13 +949,13 @@
       }
     },
     "node_modules/@vitest/mocker": {
-      "version": "3.0.4",
-      "resolved": "https://registry.npmjs.org/@vitest/mocker/-/mocker-3.0.4.tgz",
-      "integrity": "sha512-gEef35vKafJlfQbnyOXZ0Gcr9IBUsMTyTLXsEQwuyYAerpHqvXhzdBnDFuHLpFqth3F7b6BaFr4qV/Cs1ULx5A==",
+      "version": "3.0.9",
+      "resolved": "https://registry.npmjs.org/@vitest/mocker/-/mocker-3.0.9.tgz",
+      "integrity": "sha512-ryERPIBOnvevAkTq+L1lD+DTFBRcjueL9lOUfXsLfwP92h4e+Heb+PjiqS3/OURWPtywfafK0kj++yDFjWUmrA==",
       "dev": true,
       "license": "MIT",
       "dependencies": {
-        "@vitest/spy": "3.0.4",
+        "@vitest/spy": "3.0.9",
         "estree-walker": "^3.0.3",
         "magic-string": "^0.30.17"
       },
@@ -977,9 +976,9 @@
       }
     },
     "node_modules/@vitest/pretty-format": {
-      "version": "3.0.4",
-      "resolved": "https://registry.npmjs.org/@vitest/pretty-format/-/pretty-format-3.0.4.tgz",
-      "integrity": "sha512-ts0fba+dEhK2aC9PFuZ9LTpULHpY/nd6jhAQ5IMU7Gaj7crPCTdCFfgvXxruRBLFS+MLraicCuFXxISEq8C93g==",
+      "version": "3.0.9",
+      "resolved": "https://registry.npmjs.org/@vitest/pretty-format/-/pretty-format-3.0.9.tgz",
+      "integrity": "sha512-OW9F8t2J3AwFEwENg3yMyKWweF7oRJlMyHOMIhO5F3n0+cgQAJZBjNgrF8dLwFTEXl5jUqBLXd9QyyKv8zEcmA==",
       "dev": true,
       "license": "MIT",
       "dependencies": {
@@ -990,38 +989,38 @@
       }
     },
     "node_modules/@vitest/runner": {
-      "version": "3.0.4",
-      "resolved": "https://registry.npmjs.org/@vitest/runner/-/runner-3.0.4.tgz",
-      "integrity": "sha512-dKHzTQ7n9sExAcWH/0sh1elVgwc7OJ2lMOBrAm73J7AH6Pf9T12Zh3lNE1TETZaqrWFXtLlx3NVrLRb5hCK+iw==",
+      "version": "3.0.9",
+      "resolved": "https://registry.npmjs.org/@vitest/runner/-/runner-3.0.9.tgz",
+      "integrity": "sha512-NX9oUXgF9HPfJSwl8tUZCMP1oGx2+Sf+ru6d05QjzQz4OwWg0psEzwY6VexP2tTHWdOkhKHUIZH+fS6nA7jfOw==",
       "dev": true,
       "license": "MIT",
       "dependencies": {
-        "@vitest/utils": "3.0.4",
-        "pathe": "^2.0.2"
+        "@vitest/utils": "3.0.9",
+        "pathe": "^2.0.3"
       },
       "funding": {
         "url": "https://opencollective.com/vitest"
       }
     },
     "node_modules/@vitest/snapshot": {
-      "version": "3.0.4",
-      "resolved": "https://registry.npmjs.org/@vitest/snapshot/-/snapshot-3.0.4.tgz",
-      "integrity": "sha512-+p5knMLwIk7lTQkM3NonZ9zBewzVp9EVkVpvNta0/PlFWpiqLaRcF4+33L1it3uRUCh0BGLOaXPPGEjNKfWb4w==",
+      "version": "3.0.9",
+      "resolved": "https://registry.npmjs.org/@vitest/snapshot/-/snapshot-3.0.9.tgz",
+      "integrity": "sha512-AiLUiuZ0FuA+/8i19mTYd+re5jqjEc2jZbgJ2up0VY0Ddyyxg/uUtBDpIFAy4uzKaQxOW8gMgBdAJJ2ydhu39A==",
       "dev": true,
       "license": "MIT",
       "dependencies": {
-        "@vitest/pretty-format": "3.0.4",
+        "@vitest/pretty-format": "3.0.9",
         "magic-string": "^0.30.17",
-        "pathe": "^2.0.2"
+        "pathe": "^2.0.3"
       },
       "funding": {
         "url": "https://opencollective.com/vitest"
       }
     },
     "node_modules/@vitest/spy": {
-      "version": "3.0.4",
-      "resolved": "https://registry.npmjs.org/@vitest/spy/-/spy-3.0.4.tgz",
-      "integrity": "sha512-sXIMF0oauYyUy2hN49VFTYodzEAu744MmGcPR3ZBsPM20G+1/cSW/n1U+3Yu/zHxX2bIDe1oJASOkml+osTU6Q==",
+      "version": "3.0.9",
+      "resolved": "https://registry.npmjs.org/@vitest/spy/-/spy-3.0.9.tgz",
+      "integrity": "sha512-/CcK2UDl0aQ2wtkp3YVWldrpLRNCfVcIOFGlVGKO4R5eajsH393Z1yiXLVQ7vWsj26JOEjeZI0x5sm5P4OGUNQ==",
       "dev": true,
       "license": "MIT",
       "dependencies": {
@@ -1032,14 +1031,14 @@
       }
     },
     "node_modules/@vitest/utils": {
-      "version": "3.0.4",
-      "resolved": "https://registry.npmjs.org/@vitest/utils/-/utils-3.0.4.tgz",
-      "integrity": "sha512-8BqC1ksYsHtbWH+DfpOAKrFw3jl3Uf9J7yeFh85Pz52IWuh1hBBtyfEbRNNZNjl8H8A5yMLH9/t+k7HIKzQcZQ==",
+      "version": "3.0.9",
+      "resolved": "https://registry.npmjs.org/@vitest/utils/-/utils-3.0.9.tgz",
+      "integrity": "sha512-ilHM5fHhZ89MCp5aAaM9uhfl1c2JdxVxl3McqsdVyVNN6JffnEen8UMCdRTzOhGXNQGo5GNL9QugHrz727Wnng==",
       "dev": true,
       "license": "MIT",
       "dependencies": {
-        "@vitest/pretty-format": "3.0.4",
-        "loupe": "^3.1.2",
+        "@vitest/pretty-format": "3.0.9",
+        "loupe": "^3.1.3",
         "tinyrainbow": "^2.0.0"
       },
       "funding": {
@@ -1150,13 +1149,13 @@
       }
     },
     "node_modules/bare-os": {
-      "version": "3.4.0",
-      "resolved": "https://registry.npmjs.org/bare-os/-/bare-os-3.4.0.tgz",
-      "integrity": "sha512-9Ous7UlnKbe3fMi7Y+qh0DwAup6A1JkYgPnjvMDNOlmnxNRQvQ/7Nst+OnUQKzk0iAT0m9BisbDVp9gCv8+ETA==",
+      "version": "3.6.0",
+      "resolved": "https://registry.npmjs.org/bare-os/-/bare-os-3.6.0.tgz",
+      "integrity": "sha512-BUrFS5TqSBdA0LwHop4OjPJwisqxGy6JsWVqV6qaFoe965qqtaKfDzHY5T2YA1gUL0ZeeQeA+4BBc1FJTcHiPw==",
       "license": "Apache-2.0",
       "optional": true,
       "engines": {
-        "bare": ">=1.6.0"
+        "bare": ">=1.14.0"
       }
     },
     "node_modules/bare-path": {
@@ -1170,9 +1169,9 @@
       }
     },
     "node_modules/bare-stream": {
-      "version": "2.6.4",
-      "resolved": "https://registry.npmjs.org/bare-stream/-/bare-stream-2.6.4.tgz",
-      "integrity": "sha512-G6i3A74FjNq4nVrrSTUz5h3vgXzBJnjmWAVlBWaZETkgu+LgKd7AiyOml3EDJY1AHlIbBHKDXE+TUT53Ff8OaA==",
+      "version": "2.6.5",
+      "resolved": "https://registry.npmjs.org/bare-stream/-/bare-stream-2.6.5.tgz",
+      "integrity": "sha512-jSmxKJNJmHySi6hC42zlZnq00rga4jjxcgNZjY9N5WlOe/iOoGRtdwGsHzQv2RlH2KOYMwGUXhf2zXd32BA9RA==",
       "license": "Apache-2.0",
       "optional": true,
       "dependencies": {
@@ -1191,26 +1190,6 @@
         }
       }
     },
-    "node_modules/base64-js": {
-      "version": "1.5.1",
-      "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz",
-      "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==",
-      "funding": [
-        {
-          "type": "github",
-          "url": "https://github.com/sponsors/feross"
-        },
-        {
-          "type": "patreon",
-          "url": "https://www.patreon.com/feross"
-        },
-        {
-          "type": "consulting",
-          "url": "https://feross.org/support"
-        }
-      ],
-      "license": "MIT"
-    },
     "node_modules/basic-ftp": {
       "version": "5.0.5",
       "resolved": "https://registry.npmjs.org/basic-ftp/-/basic-ftp-5.0.5.tgz",
@@ -1229,30 +1208,6 @@
         "balanced-match": "^1.0.0"
       }
     },
-    "node_modules/buffer": {
-      "version": "5.7.1",
-      "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz",
-      "integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==",
-      "funding": [
-        {
-          "type": "github",
-          "url": "https://github.com/sponsors/feross"
-        },
-        {
-          "type": "patreon",
-          "url": "https://www.patreon.com/feross"
-        },
-        {
-          "type": "consulting",
-          "url": "https://feross.org/support"
-        }
-      ],
-      "license": "MIT",
-      "dependencies": {
-        "base64-js": "^1.3.1",
-        "ieee754": "^1.1.13"
-      }
-    },
     "node_modules/buffer-crc32": {
       "version": "0.2.13",
       "resolved": "https://registry.npmjs.org/buffer-crc32/-/buffer-crc32-0.2.13.tgz",
@@ -1290,9 +1245,9 @@
       }
     },
     "node_modules/chai": {
-      "version": "5.1.2",
-      "resolved": "https://registry.npmjs.org/chai/-/chai-5.1.2.tgz",
-      "integrity": "sha512-aGtmf24DW6MLHHG5gCx4zaI3uBq3KRtxeVs0DjFH6Z0rDNbsvTxFASFvdj79pxjxZ8/5u3PIiN3IwEIQkiiuPw==",
+      "version": "5.2.0",
+      "resolved": "https://registry.npmjs.org/chai/-/chai-5.2.0.tgz",
+      "integrity": "sha512-mCuXncKXk5iCLhfhwTc0izo0gtEmpz5CtG2y8GiOINBlMVS6v8TMRc5TaLWKS6692m9+dVVfzgeVxR5UxWHTYw==",
       "dev": true,
       "license": "MIT",
       "dependencies": {
@@ -1337,13 +1292,13 @@
       }
     },
     "node_modules/chromium-bidi": {
-      "version": "1.1.0",
-      "resolved": "https://registry.npmjs.org/chromium-bidi/-/chromium-bidi-1.1.0.tgz",
-      "integrity": "sha512-HislCEczCuamWm3+55Lig9XKmMF13K+BGKum9rwtDAzgUAHT4h5jNwhDmD4U20VoVUG8ujnv9UZ89qiIf5uF8w==",
+      "version": "2.1.2",
+      "resolved": "https://registry.npmjs.org/chromium-bidi/-/chromium-bidi-2.1.2.tgz",
+      "integrity": "sha512-vtRWBK2uImo5/W2oG6/cDkkHSm+2t6VHgnj+Rcwhb0pP74OoUb4GipyRX/T/y39gYQPhioP0DPShn+A7P6CHNw==",
       "license": "Apache-2.0",
       "dependencies": {
-        "mitt": "3.0.1",
-        "zod": "3.24.1"
+        "mitt": "^3.0.1",
+        "zod": "^3.24.1"
       },
       "peerDependencies": {
         "devtools-protocol": "*"
@@ -1623,9 +1578,9 @@
       }
     },
     "node_modules/devtools-protocol": {
-      "version": "0.0.1380148",
-      "resolved": "https://registry.npmjs.org/devtools-protocol/-/devtools-protocol-0.0.1380148.tgz",
-      "integrity": "sha512-1CJABgqLxbYxVI+uJY/UDUHJtJ0KZTSjNYJYKqd9FRoXT33WDakDHNxRapMEgzeJ/C3rcs01+avshMnPmKQbvA==",
+      "version": "0.0.1413902",
+      "resolved": "https://registry.npmjs.org/devtools-protocol/-/devtools-protocol-0.0.1413902.tgz",
+      "integrity": "sha512-yRtvFD8Oyk7C9Os3GmnFZLu53yAfsnyw1s+mLmHHUK0GQEc9zthHWvS1r67Zqzm5t7v56PILHIVZ7kmFMaL2yQ==",
       "license": "BSD-3-Clause"
     },
     "node_modules/eastasianwidth": {
@@ -1673,9 +1628,9 @@
       "license": "MIT"
     },
     "node_modules/esbuild": {
-      "version": "0.24.2",
-      "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.24.2.tgz",
-      "integrity": "sha512-+9egpBW8I3CD5XPe0n6BfT5fxLzxrlDzqydF3aviG+9ni1lDC/OvMHcxqEFV0+LANZG5R1bFMWfUrjVsdwxJvA==",
+      "version": "0.25.1",
+      "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.25.1.tgz",
+      "integrity": "sha512-BGO5LtrGC7vxnqucAe/rmvKdJllfGaYWdyABvyMoXQlfYMb2bbRuReWR5tEGE//4LcNJj9XrkovTqNYRFZHAMQ==",
       "dev": true,
       "hasInstallScript": true,
       "license": "MIT",
@@ -1686,31 +1641,31 @@
         "node": ">=18"
       },
       "optionalDependencies": {
-        "@esbuild/aix-ppc64": "0.24.2",
-        "@esbuild/android-arm": "0.24.2",
-        "@esbuild/android-arm64": "0.24.2",
-        "@esbuild/android-x64": "0.24.2",
-        "@esbuild/darwin-arm64": "0.24.2",
-        "@esbuild/darwin-x64": "0.24.2",
-        "@esbuild/freebsd-arm64": "0.24.2",
-        "@esbuild/freebsd-x64": "0.24.2",
-        "@esbuild/linux-arm": "0.24.2",
-        "@esbuild/linux-arm64": "0.24.2",
-        "@esbuild/linux-ia32": "0.24.2",
-        "@esbuild/linux-loong64": "0.24.2",
-        "@esbuild/linux-mips64el": "0.24.2",
-        "@esbuild/linux-ppc64": "0.24.2",
-        "@esbuild/linux-riscv64": "0.24.2",
-        "@esbuild/linux-s390x": "0.24.2",
-        "@esbuild/linux-x64": "0.24.2",
-        "@esbuild/netbsd-arm64": "0.24.2",
-        "@esbuild/netbsd-x64": "0.24.2",
-        "@esbuild/openbsd-arm64": "0.24.2",
-        "@esbuild/openbsd-x64": "0.24.2",
-        "@esbuild/sunos-x64": "0.24.2",
-        "@esbuild/win32-arm64": "0.24.2",
-        "@esbuild/win32-ia32": "0.24.2",
-        "@esbuild/win32-x64": "0.24.2"
+        "@esbuild/aix-ppc64": "0.25.1",
+        "@esbuild/android-arm": "0.25.1",
+        "@esbuild/android-arm64": "0.25.1",
+        "@esbuild/android-x64": "0.25.1",
+        "@esbuild/darwin-arm64": "0.25.1",
+        "@esbuild/darwin-x64": "0.25.1",
+        "@esbuild/freebsd-arm64": "0.25.1",
+        "@esbuild/freebsd-x64": "0.25.1",
+        "@esbuild/linux-arm": "0.25.1",
+        "@esbuild/linux-arm64": "0.25.1",
+        "@esbuild/linux-ia32": "0.25.1",
+        "@esbuild/linux-loong64": "0.25.1",
+        "@esbuild/linux-mips64el": "0.25.1",
+        "@esbuild/linux-ppc64": "0.25.1",
+        "@esbuild/linux-riscv64": "0.25.1",
+        "@esbuild/linux-s390x": "0.25.1",
+        "@esbuild/linux-x64": "0.25.1",
+        "@esbuild/netbsd-arm64": "0.25.1",
+        "@esbuild/netbsd-x64": "0.25.1",
+        "@esbuild/openbsd-arm64": "0.25.1",
+        "@esbuild/openbsd-x64": "0.25.1",
+        "@esbuild/sunos-x64": "0.25.1",
+        "@esbuild/win32-arm64": "0.25.1",
+        "@esbuild/win32-ia32": "0.25.1",
+        "@esbuild/win32-x64": "0.25.1"
       }
     },
     "node_modules/escalade": {
@@ -1987,26 +1942,6 @@
         "node": ">= 14"
       }
     },
-    "node_modules/ieee754": {
-      "version": "1.2.1",
-      "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz",
-      "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==",
-      "funding": [
-        {
-          "type": "github",
-          "url": "https://github.com/sponsors/feross"
-        },
-        {
-          "type": "patreon",
-          "url": "https://www.patreon.com/feross"
-        },
-        {
-          "type": "consulting",
-          "url": "https://feross.org/support"
-        }
-      ],
-      "license": "BSD-3-Clause"
-    },
     "node_modules/ignore": {
       "version": "7.0.3",
       "resolved": "https://registry.npmjs.org/ignore/-/ignore-7.0.3.tgz",
@@ -2998,9 +2933,9 @@
       "license": "MIT"
     },
     "node_modules/nanoid": {
-      "version": "3.3.8",
-      "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.8.tgz",
-      "integrity": "sha512-WNLf5Sd8oZxOm+TzppcYk8gVOgP+l58xNy58D0nbUnOxOWRWvlcCV4kUF7ltmI6PsrLl/BgKEyS4mqsGChFN0w==",
+      "version": "3.3.10",
+      "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.10.tgz",
+      "integrity": "sha512-vSJJTG+t/dIKAUhUDw/dLdZ9s//5OxcHqLaDWWrW4Cdq7o6tdLIczUkMXt2MBNmk6sJRZBZRXVixs7URY1CmIg==",
       "dev": true,
       "funding": [
         {
@@ -3050,9 +2985,9 @@
       }
     },
     "node_modules/ora": {
-      "version": "8.1.1",
-      "resolved": "https://registry.npmjs.org/ora/-/ora-8.1.1.tgz",
-      "integrity": "sha512-YWielGi1XzG1UTvOaCFaNgEnuhZVMSHYkW/FQ7UX8O26PtlpdM84c0f7wLPlkvx2RfiQmnzd61d/MGxmpQeJPw==",
+      "version": "8.2.0",
+      "resolved": "https://registry.npmjs.org/ora/-/ora-8.2.0.tgz",
+      "integrity": "sha512-weP+BZ8MVNnlCm8c0Qdc1WSWq4Qn7I+9CJGm7Qali6g44e/PUzbjNqJX5NJ9ljlNMosfJvg1fKEGILklK9cwnw==",
       "license": "MIT",
       "dependencies": {
         "chalk": "^5.3.0",
@@ -3096,9 +3031,9 @@
       }
     },
     "node_modules/pac-proxy-agent": {
-      "version": "7.1.0",
-      "resolved": "https://registry.npmjs.org/pac-proxy-agent/-/pac-proxy-agent-7.1.0.tgz",
-      "integrity": "sha512-Z5FnLVVZSnX7WjBg0mhDtydeRZ1xMcATZThjySQUHqr+0ksP8kqaw23fNKkaaN/Z8gwLUs/W7xdl0I75eP2Xyw==",
+      "version": "7.2.0",
+      "resolved": "https://registry.npmjs.org/pac-proxy-agent/-/pac-proxy-agent-7.2.0.tgz",
+      "integrity": "sha512-TEB8ESquiLMc0lV8vcd5Ql/JAKAoyzHFXaStwjkzpOpC5Yv+pIzLfHvjTSdf3vpa2bMiUQrg9i6276yn8666aA==",
       "license": "MIT",
       "dependencies": {
         "@tootallnate/quickjs-emscripten": "^0.23.0",
@@ -3186,9 +3121,9 @@
       }
     },
     "node_modules/pathe": {
-      "version": "2.0.2",
-      "resolved": "https://registry.npmjs.org/pathe/-/pathe-2.0.2.tgz",
-      "integrity": "sha512-15Ztpk+nov8DR524R4BF7uEuzESgzUEAV4Ah7CUMNGXdE5ELuvxElxGXndBl32vMSsWa1jpNf22Z+Er3sKwq+w==",
+      "version": "2.0.3",
+      "resolved": "https://registry.npmjs.org/pathe/-/pathe-2.0.3.tgz",
+      "integrity": "sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w==",
       "dev": true,
       "license": "MIT"
     },
@@ -3215,9 +3150,9 @@
       "license": "ISC"
     },
     "node_modules/postcss": {
-      "version": "8.5.1",
-      "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.1.tgz",
-      "integrity": "sha512-6oz2beyjc5VMn/KV1pPw8fliQkhBXrVn1Z3TVyqZxU8kZpzEKhBdmCFqI6ZbmGtamQvQGuU1sgPTk8ZrXDD7jQ==",
+      "version": "8.5.3",
+      "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.3.tgz",
+      "integrity": "sha512-dle9A3yYxlBSrt8Fu+IpjGT8SY8hN0mlaA6GY8t0P5PjIOZemULz/E2Bnm/2dcUOena75OTNkHI76uZBNUUq3A==",
       "dev": true,
       "funding": [
         {
@@ -3297,17 +3232,17 @@
       }
     },
     "node_modules/puppeteer": {
-      "version": "24.1.1",
-      "resolved": "https://registry.npmjs.org/puppeteer/-/puppeteer-24.1.1.tgz",
-      "integrity": "sha512-fuhceZ5HZuDXVuaMIRxUuDHfCJLmK0pXh8FlzVQ0/+OApStevxZhU5kAVeYFOEqeCF5OoAyZjcWbdQK27xW/9A==",
+      "version": "24.4.0",
+      "resolved": "https://registry.npmjs.org/puppeteer/-/puppeteer-24.4.0.tgz",
+      "integrity": "sha512-E4JhJzjS8AAI+6N/b+Utwarhz6zWl3+MR725fal+s3UlOlX2eWdsvYYU+Q5bXMjs9eZEGkNQroLkn7j11s2k1Q==",
       "hasInstallScript": true,
       "license": "Apache-2.0",
       "dependencies": {
-        "@puppeteer/browsers": "2.7.0",
-        "chromium-bidi": "1.1.0",
+        "@puppeteer/browsers": "2.8.0",
+        "chromium-bidi": "2.1.2",
         "cosmiconfig": "^9.0.0",
-        "devtools-protocol": "0.0.1380148",
-        "puppeteer-core": "24.1.1",
+        "devtools-protocol": "0.0.1413902",
+        "puppeteer-core": "24.4.0",
         "typed-query-selector": "^2.12.0"
       },
       "bin": {
@@ -3318,26 +3253,27 @@
       }
     },
     "node_modules/puppeteer-core": {
-      "version": "24.1.1",
-      "resolved": "https://registry.npmjs.org/puppeteer-core/-/puppeteer-core-24.1.1.tgz",
-      "integrity": "sha512-7FF3gq6bpIsbq3I8mfbodXh3DCzXagoz3l2eGv1cXooYU4g0P4mcHQVHuBD4iSZPXNg8WjzlP5kmRwK9UvwF0A==",
+      "version": "24.4.0",
+      "resolved": "https://registry.npmjs.org/puppeteer-core/-/puppeteer-core-24.4.0.tgz",
+      "integrity": "sha512-eFw66gCnWo0X8Hyf9KxxJtms7a61NJVMiSaWfItsFPzFBsjsWdmcNlBdsA1WVwln6neoHhsG+uTVesKmTREn/g==",
       "license": "Apache-2.0",
       "dependencies": {
-        "@puppeteer/browsers": "2.7.0",
-        "chromium-bidi": "1.1.0",
+        "@puppeteer/browsers": "2.8.0",
+        "chromium-bidi": "2.1.2",
         "debug": "^4.4.0",
-        "devtools-protocol": "0.0.1380148",
+        "devtools-protocol": "0.0.1413902",
         "typed-query-selector": "^2.12.0",
-        "ws": "^8.18.0"
+        "ws": "^8.18.1"
       },
       "engines": {
         "node": ">=18"
       }
     },
     "node_modules/remark-gfm": {
-      "version": "4.0.0",
-      "resolved": "https://registry.npmjs.org/remark-gfm/-/remark-gfm-4.0.0.tgz",
-      "integrity": "sha512-U92vJgBPkbw4Zfu/IiW2oTZLSL3Zpv+uI7My2eq8JxKgqraFdU8YUGicEJCEgSbeaG+QDFqIcwwfMTOEelPxuA==",
+      "version": "4.0.1",
+      "resolved": "https://registry.npmjs.org/remark-gfm/-/remark-gfm-4.0.1.tgz",
+      "integrity": "sha512-1quofZ2RQ9EWdeN34S79+KExV1764+wCUGop5CPL1WGdD0ocPpu91lzPGbwWMECpEpd42kJGQwzRfyov9j4yNg==",
+      "license": "MIT",
       "dependencies": {
         "@types/mdast": "^4.0.0",
         "mdast-util-gfm": "^3.0.0",
@@ -3414,9 +3350,9 @@
       }
     },
     "node_modules/rollup": {
-      "version": "4.32.1",
-      "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.32.1.tgz",
-      "integrity": "sha512-z+aeEsOeEa3mEbS1Tjl6sAZ8NE3+AalQz1RJGj81M+fizusbdDMoEJwdJNHfaB40Scr4qNu+welOfes7maKonA==",
+      "version": "4.36.0",
+      "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.36.0.tgz",
+      "integrity": "sha512-zwATAXNQxUcd40zgtQG0ZafcRK4g004WtEl7kbuhTWPvf07PsfohXl39jVUvPF7jvNAIkKPQ2XrsDlWuxBd++Q==",
       "dev": true,
       "license": "MIT",
       "dependencies": {
@@ -3430,32 +3366,32 @@
         "npm": ">=8.0.0"
       },
       "optionalDependencies": {
-        "@rollup/rollup-android-arm-eabi": "4.32.1",
-        "@rollup/rollup-android-arm64": "4.32.1",
-        "@rollup/rollup-darwin-arm64": "4.32.1",
-        "@rollup/rollup-darwin-x64": "4.32.1",
-        "@rollup/rollup-freebsd-arm64": "4.32.1",
-        "@rollup/rollup-freebsd-x64": "4.32.1",
-        "@rollup/rollup-linux-arm-gnueabihf": "4.32.1",
-        "@rollup/rollup-linux-arm-musleabihf": "4.32.1",
-        "@rollup/rollup-linux-arm64-gnu": "4.32.1",
-        "@rollup/rollup-linux-arm64-musl": "4.32.1",
-        "@rollup/rollup-linux-loongarch64-gnu": "4.32.1",
-        "@rollup/rollup-linux-powerpc64le-gnu": "4.32.1",
-        "@rollup/rollup-linux-riscv64-gnu": "4.32.1",
-        "@rollup/rollup-linux-s390x-gnu": "4.32.1",
-        "@rollup/rollup-linux-x64-gnu": "4.32.1",
-        "@rollup/rollup-linux-x64-musl": "4.32.1",
-        "@rollup/rollup-win32-arm64-msvc": "4.32.1",
-        "@rollup/rollup-win32-ia32-msvc": "4.32.1",
-        "@rollup/rollup-win32-x64-msvc": "4.32.1",
+        "@rollup/rollup-android-arm-eabi": "4.36.0",
+        "@rollup/rollup-android-arm64": "4.36.0",
+        "@rollup/rollup-darwin-arm64": "4.36.0",
+        "@rollup/rollup-darwin-x64": "4.36.0",
+        "@rollup/rollup-freebsd-arm64": "4.36.0",
+        "@rollup/rollup-freebsd-x64": "4.36.0",
+        "@rollup/rollup-linux-arm-gnueabihf": "4.36.0",
+        "@rollup/rollup-linux-arm-musleabihf": "4.36.0",
+        "@rollup/rollup-linux-arm64-gnu": "4.36.0",
+        "@rollup/rollup-linux-arm64-musl": "4.36.0",
+        "@rollup/rollup-linux-loongarch64-gnu": "4.36.0",
+        "@rollup/rollup-linux-powerpc64le-gnu": "4.36.0",
+        "@rollup/rollup-linux-riscv64-gnu": "4.36.0",
+        "@rollup/rollup-linux-s390x-gnu": "4.36.0",
+        "@rollup/rollup-linux-x64-gnu": "4.36.0",
+        "@rollup/rollup-linux-x64-musl": "4.36.0",
+        "@rollup/rollup-win32-arm64-msvc": "4.36.0",
+        "@rollup/rollup-win32-ia32-msvc": "4.36.0",
+        "@rollup/rollup-win32-x64-msvc": "4.36.0",
         "fsevents": "~2.3.2"
       }
     },
     "node_modules/semver": {
-      "version": "7.6.3",
-      "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.3.tgz",
-      "integrity": "sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==",
+      "version": "7.7.1",
+      "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.1.tgz",
+      "integrity": "sha512-hlq8tAfn0m/61p4BVRcPzIGr6LKiMwo4VM6dGi6pt4qcRkmNzTcWq6eCEjEh+qXjkMDvPlOFFSGwQjoEa6gyMA==",
       "license": "ISC",
       "bin": {
         "semver": "bin/semver.js"
@@ -3512,9 +3448,9 @@
       }
     },
     "node_modules/socks": {
-      "version": "2.8.3",
-      "resolved": "https://registry.npmjs.org/socks/-/socks-2.8.3.tgz",
-      "integrity": "sha512-l5x7VUUWbjVFbafGLxPWkYsHIhEvmF85tbIeFZWc8ZPtoMyybuEhL7Jye/ooC4/d48FgOjSJXgsF/AJPYCW8Zw==",
+      "version": "2.8.4",
+      "resolved": "https://registry.npmjs.org/socks/-/socks-2.8.4.tgz",
+      "integrity": "sha512-D3YaD0aRxR3mEcqnidIs7ReYJFVzWdd6fXJYUM8ixcQcJRGTka/b3saV0KflYhyVJXKhb947GndU35SxYNResQ==",
       "license": "MIT",
       "dependencies": {
         "ip-address": "^9.0.5",
@@ -3744,12 +3680,6 @@
         "b4a": "^1.6.4"
       }
     },
-    "node_modules/through": {
-      "version": "2.3.8",
-      "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz",
-      "integrity": "sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg==",
-      "license": "MIT"
-    },
     "node_modules/tinybench": {
       "version": "2.9.0",
       "resolved": "https://registry.npmjs.org/tinybench/-/tinybench-2.9.0.tgz",
@@ -3815,16 +3745,6 @@
       "integrity": "sha512-SbklCd1F0EiZOyPiW192rrHZzZ5sBijB6xM+cpmrwDqObvdtunOHHIk9fCGsoK5JVIYXoyEp4iEdE3upFH3PAg==",
       "license": "MIT"
     },
-    "node_modules/unbzip2-stream": {
-      "version": "1.4.3",
-      "resolved": "https://registry.npmjs.org/unbzip2-stream/-/unbzip2-stream-1.4.3.tgz",
-      "integrity": "sha512-mlExGW4w71ebDJviH16lQLtZS32VKqsSfk80GCfUlwT/4/hNRFsoscrF/c++9xinkMzECL1uL9DDwXqFWkruPg==",
-      "license": "MIT",
-      "dependencies": {
-        "buffer": "^5.2.1",
-        "through": "^2.3.8"
-      }
-    },
     "node_modules/undici-types": {
       "version": "6.20.0",
       "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.20.0.tgz",
@@ -3930,15 +3850,15 @@
       }
     },
     "node_modules/vite": {
-      "version": "6.0.11",
-      "resolved": "https://registry.npmjs.org/vite/-/vite-6.0.11.tgz",
-      "integrity": "sha512-4VL9mQPKoHy4+FE0NnRE/kbY51TOfaknxAjt3fJbGJxhIpBZiqVzlZDEesWWsuREXHwNdAoOFZ9MkPEVXczHwg==",
+      "version": "6.2.2",
+      "resolved": "https://registry.npmjs.org/vite/-/vite-6.2.2.tgz",
+      "integrity": "sha512-yW7PeMM+LkDzc7CgJuRLMW2Jz0FxMOsVJ8Lv3gpgW9WLcb9cTW+121UEr1hvmfR7w3SegR5ItvYyzVz1vxNJgQ==",
       "dev": true,
       "license": "MIT",
       "dependencies": {
-        "esbuild": "^0.24.2",
-        "postcss": "^8.4.49",
-        "rollup": "^4.23.0"
+        "esbuild": "^0.25.0",
+        "postcss": "^8.5.3",
+        "rollup": "^4.30.1"
       },
       "bin": {
         "vite": "bin/vite.js"
@@ -4002,16 +3922,16 @@
       }
     },
     "node_modules/vite-node": {
-      "version": "3.0.4",
-      "resolved": "https://registry.npmjs.org/vite-node/-/vite-node-3.0.4.tgz",
-      "integrity": "sha512-7JZKEzcYV2Nx3u6rlvN8qdo3QV7Fxyt6hx+CCKz9fbWxdX5IvUOmTWEAxMrWxaiSf7CKGLJQ5rFu8prb/jBjOA==",
+      "version": "3.0.9",
+      "resolved": "https://registry.npmjs.org/vite-node/-/vite-node-3.0.9.tgz",
+      "integrity": "sha512-w3Gdx7jDcuT9cNn9jExXgOyKmf5UOTb6WMHz8LGAm54eS1Elf5OuBhCxl6zJxGhEeIkgsE1WbHuoL0mj/UXqXg==",
       "dev": true,
       "license": "MIT",
       "dependencies": {
         "cac": "^6.7.14",
         "debug": "^4.4.0",
         "es-module-lexer": "^1.6.0",
-        "pathe": "^2.0.2",
+        "pathe": "^2.0.3",
         "vite": "^5.0.0 || ^6.0.0"
       },
       "bin": {
@@ -4025,31 +3945,31 @@
       }
     },
     "node_modules/vitest": {
-      "version": "3.0.4",
-      "resolved": "https://registry.npmjs.org/vitest/-/vitest-3.0.4.tgz",
-      "integrity": "sha512-6XG8oTKy2gnJIFTHP6LD7ExFeNLxiTkK3CfMvT7IfR8IN+BYICCf0lXUQmX7i7JoxUP8QmeP4mTnWXgflu4yjw==",
+      "version": "3.0.9",
+      "resolved": "https://registry.npmjs.org/vitest/-/vitest-3.0.9.tgz",
+      "integrity": "sha512-BbcFDqNyBlfSpATmTtXOAOj71RNKDDvjBM/uPfnxxVGrG+FSH2RQIwgeEngTaTkuU/h0ScFvf+tRcKfYXzBybQ==",
       "dev": true,
       "license": "MIT",
       "dependencies": {
-        "@vitest/expect": "3.0.4",
-        "@vitest/mocker": "3.0.4",
-        "@vitest/pretty-format": "^3.0.4",
-        "@vitest/runner": "3.0.4",
-        "@vitest/snapshot": "3.0.4",
-        "@vitest/spy": "3.0.4",
-        "@vitest/utils": "3.0.4",
-        "chai": "^5.1.2",
+        "@vitest/expect": "3.0.9",
+        "@vitest/mocker": "3.0.9",
+        "@vitest/pretty-format": "^3.0.9",
+        "@vitest/runner": "3.0.9",
+        "@vitest/snapshot": "3.0.9",
+        "@vitest/spy": "3.0.9",
+        "@vitest/utils": "3.0.9",
+        "chai": "^5.2.0",
         "debug": "^4.4.0",
         "expect-type": "^1.1.0",
         "magic-string": "^0.30.17",
-        "pathe": "^2.0.2",
+        "pathe": "^2.0.3",
         "std-env": "^3.8.0",
         "tinybench": "^2.9.0",
         "tinyexec": "^0.3.2",
         "tinypool": "^1.0.2",
         "tinyrainbow": "^2.0.0",
         "vite": "^5.0.0 || ^6.0.0",
-        "vite-node": "3.0.4",
+        "vite-node": "3.0.9",
         "why-is-node-running": "^2.3.0"
       },
       "bin": {
@@ -4065,8 +3985,8 @@
         "@edge-runtime/vm": "*",
         "@types/debug": "^4.1.12",
         "@types/node": "^18.0.0 || ^20.0.0 || >=22.0.0",
-        "@vitest/browser": "3.0.4",
-        "@vitest/ui": "3.0.4",
+        "@vitest/browser": "3.0.9",
+        "@vitest/ui": "3.0.9",
         "happy-dom": "*",
         "jsdom": "*"
       },
@@ -4241,9 +4161,9 @@
       "license": "ISC"
     },
     "node_modules/ws": {
-      "version": "8.18.0",
-      "resolved": "https://registry.npmjs.org/ws/-/ws-8.18.0.tgz",
-      "integrity": "sha512-8VbfWfHLbbwu3+N6OKsOMpBdT4kXPDDB9cJk2bJ6mh9ucxdlnNvH1e+roYkKmN9Nxw2yjz7VzeO9oOz2zJ04Pw==",
+      "version": "8.18.1",
+      "resolved": "https://registry.npmjs.org/ws/-/ws-8.18.1.tgz",
+      "integrity": "sha512-RKW2aJZMXeMxVpnZ6bck+RswznaxmzdULiBr6KY7XkTnW8uvt0iT9H5DkHUChXrc+uurzwa0rVI16n/Xzjdz1w==",
       "license": "MIT",
       "engines": {
         "node": ">=10.0.0"
@@ -4349,9 +4269,9 @@
       }
     },
     "node_modules/zod": {
-      "version": "3.24.1",
-      "resolved": "https://registry.npmjs.org/zod/-/zod-3.24.1.tgz",
-      "integrity": "sha512-muH7gBL9sI1nciMZV67X5fTKKBLtwpZ5VBp1vsOQzj1MhrBZ4wlVCm3gedKZWLp0Oyel8sIGfeiz54Su+OVT+A==",
+      "version": "3.24.2",
+      "resolved": "https://registry.npmjs.org/zod/-/zod-3.24.2.tgz",
+      "integrity": "sha512-lY7CDW43ECgW9u1TcT3IoXHflywfVqDYze4waEz812jR/bZ8FHDsl7pFQoSZTz5N+2NqRXs8GBwnAwo3ZNxqhQ==",
       "license": "MIT",
       "funding": {
         "url": "https://github.com/sponsors/colinhacks"
diff --git a/package.json b/package.json
index 8f3f0c9..a71933e 100644
--- a/package.json
+++ b/package.json
@@ -48,14 +48,14 @@
     "joi": "^17.13.3",
     "js-yaml": "^4.1.0",
     "kleur": "^4.1.5",
-    "ora": "^8.1.1",
-    "puppeteer": "^24.1.1",
-    "remark-gfm": "^4.0.0",
+    "ora": "^8.2.0",
+    "puppeteer": "^24.4.0",
+    "remark-gfm": "^4.0.1",
     "remark-parse": "^11.0.0",
     "unified": "^11.0.5",
     "unist-util-visit": "^5.0.0"
   },
   "devDependencies": {
-    "vitest": "^3.0.4"
+    "vitest": "^3.0.9"
   }
 }


Test patch:
diff --git a/index.test.js b/index.test.js
index dd97caa..5338f8f 100644
--- a/index.test.js
+++ b/index.test.js
@@ -36,3 +36,64 @@ test('linkspector should check top-level relative links in Markdown file', async
   expect(hasErrorLinks).toBe(false)
   expect(results.length).toBe(21)
 })
+
+test('linkspector should track statistics correctly when stats option is enabled', async () => {
+  let cmd = {
+    showstat: true,
+  }
+
+  // Initialize statistics counters
+  let stats = {
+    filesChecked: 0,
+    totalLinks: 0,
+    httpLinks: 0,
+    fileLinks: 0,
+    correctLinks: 0,
+    failedLinks: 0,
+  }
+
+  for await (const { file, result } of linkspector(
+    './.linkspector.test.yml',
+    cmd
+  )) {
+    // Increment file count for statistics
+    stats.filesChecked++
+
+    for (const linkStatusObj of result) {
+      // Count total links
+      stats.totalLinks++
+
+      // Count HTTP vs File links
+      if (linkStatusObj.link.match(/^https?:\/\//)) {
+        stats.httpLinks++
+      } else if (
+        !linkStatusObj.link.startsWith('#') &&
+        !linkStatusObj.link.startsWith('mailto:')
+      ) {
+        stats.fileLinks++
+      }
+
+      // Count correct vs failed links
+      if (linkStatusObj.status === 'error') {
+        stats.failedLinks++
+      } else if (
+        linkStatusObj.status === 'alive' ||
+        linkStatusObj.status === 'assumed alive'
+      ) {
+        stats.correctLinks++
+      }
+    }
+  }
+
+  // Verify statistics are being tracked correctly
+  expect(stats.filesChecked).toBeGreaterThan(0)
+  expect(stats.totalLinks).toBe(21)
+  expect(stats.totalLinks).toBe(
+    stats.httpLinks +
+      stats.fileLinks +
+      (stats.totalLinks - stats.httpLinks - stats.fileLinks)
+  )
+  expect(stats.totalLinks).toBe(stats.correctLinks + stats.failedLinks)
+  expect(stats.correctLinks).toBeGreaterThanOrEqual(0)
+  expect(stats.failedLinks).toBe(0)
+})