Commit aeec7ae

Anton Golub <antongolub@antongolub.com>
2024-03-17 08:41:24
refactor: separate core (#733)
* chore: inject zurk * chore: handle timeouts via zurk * chore: override zurk quote * chore: use zurk response to build ProcessOutput * chore: linting * chore: use buildCmd from zurk * feat: provide preset api closes #600 * docs: add some comments * build: move zurk to vendor bundle * chore: move zurk to dev deps * feat: process quiet as preset option * refactor: use zurk/spawn * chore: linting * build: update esbuild
1 parent be0d674
scripts/build-dts.mjs
@@ -37,6 +37,7 @@ const entry = {
       '@types/minimist',
       '@types/ps-tree',
       '@types/which',
+      'zurk',
     ], // args['external-inlines'],
   },
   output: {
src/core.ts
@@ -13,11 +13,13 @@
 // limitations under the License.
 
 import assert from 'node:assert'
-import { ChildProcess, spawn, StdioNull, StdioPipe } from 'node:child_process'
+import { spawn, StdioNull, StdioPipe } from 'node:child_process'
 import { AsyncLocalStorage, createHook } from 'node:async_hooks'
 import { Readable, Writable } from 'node:stream'
 import { inspect } from 'node:util'
 import {
+  exec,
+  buildCmd,
   chalk,
   which,
   type ChalkInstance,
@@ -36,10 +38,10 @@ import {
   quotePowerShell,
 } from './util.js'
 
-export type Shell = (
-  pieces: TemplateStringsArray,
-  ...args: any[]
-) => ProcessPromise
+export interface Shell {
+  (pieces: TemplateStringsArray, ...args: any[]): ProcessPromise
+  (opts: Partial<Options>): Shell
+}
 
 const processCwd = Symbol('processCwd')
 
@@ -49,8 +51,10 @@ export interface Options {
   verbose: boolean
   env: NodeJS.ProcessEnv
   shell: string | boolean
+  nothrow: boolean
   prefix: string
   quote: typeof quote
+  quiet: boolean
   spawn: typeof spawn
   log: typeof log
 }
@@ -70,6 +74,8 @@ export const defaults: Options = {
   verbose: true,
   env: process.env,
   shell: true,
+  nothrow: false,
+  quiet: false,
   prefix: '',
   quote: () => {
     throw new Error('No quote function is defined: https://ï.at/no-quote-func')
@@ -77,13 +83,13 @@ export const defaults: Options = {
   spawn,
   log,
 }
-
+const isWin = process.platform == 'win32'
 try {
   defaults.shell = which.sync('bash')
   defaults.prefix = 'set -euo pipefail;'
   defaults.quote = quote
 } catch (err) {
-  if (process.platform == 'win32') {
+  if (isWin) {
     try {
       defaults.shell = which.sync('powershell.exe')
       defaults.quote = quotePowerShell
@@ -97,25 +103,28 @@ function getStore() {
   return storage.getStore() || defaults
 }
 
-export const $ = new Proxy<Shell & Options>(
+export const $: Shell & Options = new Proxy<Shell & Options>(
   function (pieces, ...args) {
+    if (!Array.isArray(pieces)) {
+      return function (this: any, ...args: any) {
+        const self = this
+        return within(() => {
+          return Object.assign($, pieces).apply(self, args)
+        })
+      }
+    }
     const from = new Error().stack!.split(/^\s*at\s/m)[2].trim()
     if (pieces.some((p) => p == undefined)) {
       throw new Error(`Malformed command at ${from}`)
     }
     let resolve: Resolve, reject: Resolve
     const promise = new ProcessPromise((...args) => ([resolve, reject] = args))
-    let cmd = pieces[0],
-      i = 0
-    while (i < args.length) {
-      let s
-      if (Array.isArray(args[i])) {
-        s = args[i].map((x: any) => $.quote(substitute(x))).join(' ')
-      } else {
-        s = $.quote(substitute(args[i]))
-      }
-      cmd += s + pieces[++i]
-    }
+    const cmd = buildCmd(
+      $.quote,
+      pieces as TemplateStringsArray,
+      args
+    ) as string
+
     promise._bind(cmd, from, resolve!, reject!, getStore())
     // Postpone run to allow promise configuration.
     setImmediate(() => promise.isHalted || promise.run())
@@ -145,20 +154,20 @@ type Resolve = (out: ProcessOutput) => void
 type IO = StdioPipe | StdioNull
 
 export class ProcessPromise extends Promise<ProcessOutput> {
-  child?: ChildProcess
   private _command = ''
   private _from = ''
   private _resolve: Resolve = noop
   private _reject: Resolve = noop
   private _snapshot = getStore()
   private _stdio: [IO, IO, IO] = ['inherit', 'pipe', 'pipe']
-  private _nothrow = false
-  private _quiet = false
+  private _nothrow?: boolean
+  private _quiet?: boolean
   private _timeout?: number
-  private _timeoutSignal?: string
+  private _timeoutSignal = 'SIGTERM'
   private _resolved = false
   private _halted = false
   private _piped = false
+  private zurk: ReturnType<typeof exec> | null = null
   _prerun = noop
   _postrun = noop
 
@@ -178,80 +187,89 @@ export class ProcessPromise extends Promise<ProcessOutput> {
 
   run(): ProcessPromise {
     const $ = this._snapshot
+    const self = this
     if (this.child) return this // The _run() can be called from a few places.
     this._prerun() // In case $1.pipe($2), the $2 returned, and on $2._run() invoke $1._run().
+
     $.log({
       kind: 'cmd',
       cmd: this._command,
-      verbose: $.verbose && !this._quiet,
+      verbose: self.isVerbose(),
     })
-    this.child = $.spawn($.prefix + this._command, {
+
+    this.zurk = exec({
+      cmd: $.prefix + this._command,
       cwd: $.cwd ?? $[processCwd],
       shell: typeof $.shell === 'string' ? $.shell : true,
-      stdio: this._stdio,
-      windowsHide: true,
       env: $.env,
+      spawn: $.spawn,
+      stdio: this._stdio as any,
+      sync: false,
+      detached: !isWin,
+      run: (cb) => cb(),
+      on: {
+        start: () => {
+          if (self._timeout) {
+            const t = setTimeout(
+              () => self.kill(self._timeoutSignal),
+              self._timeout
+            )
+            self.finally(() => clearTimeout(t)).catch(noop)
+          }
+        },
+        stdout: (data) => {
+          // If process is piped, don't print output.
+          if (self._piped) return
+          $.log({ kind: 'stdout', data, verbose: self.isVerbose() })
+        },
+        stderr: (data) => {
+          // Stderr should be printed regardless of piping.
+          $.log({ kind: 'stderr', data, verbose: self.isVerbose() })
+        },
+        end: ({ error, stdout, stderr, stdall, status, signal }) => {
+          self._resolved = true
+
+          if (error) {
+            const message = ProcessOutput.getErrorMessage(error, self._from)
+            // Should we enable this?
+            // (nothrow ? self._resolve : self._reject)(
+            self._reject(
+              new ProcessOutput(null, null, stdout, stderr, stdall, message)
+            )
+          } else {
+            const message = ProcessOutput.getExitMessage(
+              status,
+              signal,
+              stderr,
+              self._from
+            )
+            const output = new ProcessOutput(
+              status,
+              signal,
+              stdout,
+              stderr,
+              stdall,
+              message
+            )
+            if (status === 0 || (self._nothrow ?? $.nothrow)) {
+              self._resolve(output)
+            } else {
+              self._reject(output)
+            }
+          }
+        },
+      },
     })
-    this.child.on('close', (code, signal) => {
-      let message = `exit code: ${code}`
-      if (code != 0 || signal != null) {
-        message = `${stderr || '\n'}    at ${this._from}`
-        message += `\n    exit code: ${code}${
-          exitCodeInfo(code) ? ' (' + exitCodeInfo(code) + ')' : ''
-        }`
-        if (signal != null) {
-          message += `\n    signal: ${signal}`
-        }
-      }
-      let output = new ProcessOutput(
-        code,
-        signal,
-        stdout,
-        stderr,
-        combined,
-        message
-      )
-      if (code === 0 || this._nothrow) {
-        this._resolve(output)
-      } else {
-        this._reject(output)
-      }
-      this._resolved = true
-    })
-    this.child.on('error', (err: NodeJS.ErrnoException) => {
-      const message =
-        `${err.message}\n` +
-        `    errno: ${err.errno} (${errnoMessage(err.errno)})\n` +
-        `    code: ${err.code}\n` +
-        `    at ${this._from}`
-      this._reject(
-        new ProcessOutput(null, null, stdout, stderr, combined, message)
-      )
-      this._resolved = true
-    })
-    let stdout = '',
-      stderr = '',
-      combined = ''
-    let onStdout = (data: any) => {
-      $.log({ kind: 'stdout', data, verbose: $.verbose && !this._quiet })
-      stdout += data
-      combined += data
-    }
-    let onStderr = (data: any) => {
-      $.log({ kind: 'stderr', data, verbose: $.verbose && !this._quiet })
-      stderr += data
-      combined += data
-    }
-    if (!this._piped) this.child.stdout?.on('data', onStdout) // If process is piped, don't collect or print output.
-    this.child.stderr?.on('data', onStderr) // Stderr should be printed regardless of piping.
+
     this._postrun() // In case $1.pipe($2), after both subprocesses are running, we can pipe $1.stdout to $2.stdin.
-    if (this._timeout && this._timeoutSignal) {
-      const t = setTimeout(() => this.kill(this._timeoutSignal), this._timeout)
-      this.finally(() => clearTimeout(t)).catch(noop)
-    }
+
     return this
   }
 
+  get child() {
+    return this.zurk?.child
+  }
+
   get stdin(): Writable {
     this.stdio('pipe')
     this.run()
@@ -340,6 +358,7 @@ export class ProcessPromise extends Promise<ProcessOutput> {
     if (!this.child)
       throw new Error('Trying to kill a process without creating one.')
     if (!this.child.pid) throw new Error('The process pid is undefined.')
+
     let children = await psTree(this.child.pid)
     for (const p of children) {
       try {
@@ -347,7 +366,7 @@ export class ProcessPromise extends Promise<ProcessOutput> {
       } catch (e) {}
     }
     try {
-      process.kill(this.child.pid, signal)
+      process.kill(-this.child.pid, signal)
     } catch (e) {}
   }
 
@@ -366,6 +385,11 @@ export class ProcessPromise extends Promise<ProcessOutput> {
     return this
   }
 
+  isVerbose(): boolean {
+    const { verbose, quiet } = this._snapshot
+    return verbose && !(this._quiet ?? quiet)
+  }
+
   timeout(d: Duration, signal = 'SIGTERM'): ProcessPromise {
     this._timeout = parseDuration(d)
     this._timeoutSignal = signal
@@ -425,6 +449,35 @@ export class ProcessOutput extends Error {
     return this._signal
   }
 
+  static getExitMessage(
+    code: number | null,
+    signal: NodeJS.Signals | null,
+    stderr: string,
+    from: string
+  ) {
+    let message = `exit code: ${code}`
+    if (code != 0 || signal != null) {
+      message = `${stderr || '\n'}    at ${from}`
+      message += `\n    exit code: ${code}${
+        exitCodeInfo(code) ? ' (' + exitCodeInfo(code) + ')' : ''
+      }`
+      if (signal != null) {
+        message += `\n    signal: ${signal}`
+      }
+    }
+
+    return message
+  }
+
+  static getErrorMessage(err: NodeJS.ErrnoException, from: string) {
+    return (
+      `${err.message}\n` +
+      `    errno: ${err.errno} (${errnoMessage(err.errno)})\n` +
+      `    code: ${err.code}\n` +
+      `    at ${from}`
+    )
+  }
+
   [inspect.custom]() {
     let stringify = (s: string, c: ChalkInstance) =>
       s.length === 0 ? "''" : c(inspect(s))
src/index.ts
@@ -21,14 +21,14 @@ export { minimist, chalk, fs, which, YAML, ssh } from './vendor.js'
 export { type Duration, quote, quotePowerShell } from './util.js'
 
 /**
- *  @deprecated Use $.nothrow() instead.
+ *  @deprecated Use $`cmd`.nothrow() instead.
  */
 export function nothrow(promise: ProcessPromise) {
   return promise.nothrow()
 }
 
 /**
- * @deprecated Use $.quiet() instead.
+ * @deprecated Use $`cmd`.quiet() instead.
  */
 export function quiet(promise: ProcessPromise) {
   return promise.quiet()
src/vendor.ts
@@ -26,6 +26,8 @@ import * as yaml from 'yaml'
 import * as _fs from 'fs-extra'
 import type { fetch } from 'node-fetch-native'
 
+export { exec, buildCmd } from 'zurk/spawn'
+
 export { fetch as nodeFetch } from 'node-fetch-native'
 export type RequestInfo = Parameters<typeof fetch>[0]
 export type RequestInit = Parameters<typeof fetch>[1]
test/core.test.js
@@ -124,6 +124,11 @@ describe('core', () => {
     }
   })
 
+  test('provides presets', async () => {
+    const $$ = $({ nothrow: true })
+    assert.equal((await $$`exit 1`).exitCode, 1)
+  })
+
   test('ProcessPromise', async () => {
     let contents = ''
     let stream = new Writable({
package-lock.json
@@ -21,15 +21,14 @@
         "c8": "^7.13.0",
         "chalk": "^5.3.0",
         "dts-bundle-generator": "^9.3.1",
-        "esbuild": "^0.20.1",
+        "esbuild": "^0.20.2",
         "esbuild-node-externals": "^1.13.0",
-        "esbuild-plugin-entry-chunks": "^0.1.8",
+        "esbuild-plugin-entry-chunks": "^0.1.11",
         "fs-extra": "^11.2.0",
         "fx": "*",
         "globby": "^14.0.1",
         "madge": "^6.1.0",
         "minimist": "^1.2.8",
-        "node-fetch": "3.3.2",
         "node-fetch-native": "^1.6.2",
         "prettier": "^2.8.8",
         "ps-tree": "^1.2.0",
@@ -37,14 +36,15 @@
         "typescript": "^5.0.4",
         "webpod": "^0",
         "which": "^3.0.0",
-        "yaml": "^2.3.4"
+        "yaml": "^2.3.4",
+        "zurk": "^0.0.27"
       },
       "engines": {
         "node": ">= 16.0.0"
       },
       "optionalDependencies": {
         "@types/fs-extra": "^11.0.4",
-        "@types/node": ">=20.11.19"
+        "@types/node": ">=20.11.28"
       }
     },
     "node_modules/@ampproject/remapping": {
@@ -798,9 +798,9 @@
       "dev": true
     },
     "node_modules/@esbuild/aix-ppc64": {
-      "version": "0.20.1",
-      "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.20.1.tgz",
-      "integrity": "sha512-m55cpeupQ2DbuRGQMMZDzbv9J9PgVelPjlcmM5kxHnrBdBx6REaEd7LamYV7Dm8N7rCyR/XwU6rVP8ploKtIkA==",
+      "version": "0.20.2",
+      "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.20.2.tgz",
+      "integrity": "sha512-D+EBOJHXdNZcLJRBkhENNG8Wji2kgc9AZ9KiPr1JuZjsNtyHzrsfLRrY0tk2H2aoFu6RANO1y1iPPUCDYWkb5g==",
       "cpu": [
         "ppc64"
       ],
@@ -814,9 +814,9 @@
       }
     },
     "node_modules/@esbuild/android-arm": {
-      "version": "0.20.1",
-      "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.20.1.tgz",
-      "integrity": "sha512-4j0+G27/2ZXGWR5okcJi7pQYhmkVgb4D7UKwxcqrjhvp5TKWx3cUjgB1CGj1mfdmJBQ9VnUGgUhign+FPF2Zgw==",
+      "version": "0.20.2",
+      "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.20.2.tgz",
+      "integrity": "sha512-t98Ra6pw2VaDhqNWO2Oph2LXbz/EJcnLmKLGBJwEwXX/JAN83Fym1rU8l0JUWK6HkIbWONCSSatf4sf2NBRx/w==",
       "cpu": [
         "arm"
       ],
@@ -830,9 +830,9 @@
       }
     },
     "node_modules/@esbuild/android-arm64": {
-      "version": "0.20.1",
-      "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.20.1.tgz",
-      "integrity": "sha512-hCnXNF0HM6AjowP+Zou0ZJMWWa1VkD77BXe959zERgGJBBxB+sV+J9f/rcjeg2c5bsukD/n17RKWXGFCO5dD5A==",
+      "version": "0.20.2",
+      "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.20.2.tgz",
+      "integrity": "sha512-mRzjLacRtl/tWU0SvD8lUEwb61yP9cqQo6noDZP/O8VkwafSYwZ4yWy24kan8jE/IMERpYncRt2dw438LP3Xmg==",
       "cpu": [
         "arm64"
       ],
@@ -846,9 +846,9 @@
       }
     },
     "node_modules/@esbuild/android-x64": {
-      "version": "0.20.1",
-      "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.20.1.tgz",
-      "integrity": "sha512-MSfZMBoAsnhpS+2yMFYIQUPs8Z19ajwfuaSZx+tSl09xrHZCjbeXXMsUF/0oq7ojxYEpsSo4c0SfjxOYXRbpaA==",
+      "version": "0.20.2",
+      "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.20.2.tgz",
+      "integrity": "sha512-btzExgV+/lMGDDa194CcUQm53ncxzeBrWJcncOBxuC6ndBkKxnHdFJn86mCIgTELsooUmwUm9FkhSp5HYu00Rg==",
       "cpu": [
         "x64"
       ],
@@ -862,9 +862,9 @@
       }
     },
     "node_modules/@esbuild/darwin-arm64": {
-      "version": "0.20.1",
-      "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.20.1.tgz",
-      "integrity": "sha512-Ylk6rzgMD8klUklGPzS414UQLa5NPXZD5tf8JmQU8GQrj6BrFA/Ic9tb2zRe1kOZyCbGl+e8VMbDRazCEBqPvA==",
+      "version": "0.20.2",
+      "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.20.2.tgz",
+      "integrity": "sha512-4J6IRT+10J3aJH3l1yzEg9y3wkTDgDk7TSDFX+wKFiWjqWp/iCfLIYzGyasx9l0SAFPT1HwSCR+0w/h1ES/MjA==",
       "cpu": [
         "arm64"
       ],
@@ -878,9 +878,9 @@
       }
     },
     "node_modules/@esbuild/darwin-x64": {
-      "version": "0.20.1",
-      "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.20.1.tgz",
-      "integrity": "sha512-pFIfj7U2w5sMp52wTY1XVOdoxw+GDwy9FsK3OFz4BpMAjvZVs0dT1VXs8aQm22nhwoIWUmIRaE+4xow8xfIDZA==",
+      "version": "0.20.2",
+      "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.20.2.tgz",
+      "integrity": "sha512-tBcXp9KNphnNH0dfhv8KYkZhjc+H3XBkF5DKtswJblV7KlT9EI2+jeA8DgBjp908WEuYll6pF+UStUCfEpdysA==",
       "cpu": [
         "x64"
       ],
@@ -894,9 +894,9 @@
       }
     },
     "node_modules/@esbuild/freebsd-arm64": {
-      "version": "0.20.1",
-      "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.20.1.tgz",
-      "integrity": "sha512-UyW1WZvHDuM4xDz0jWun4qtQFauNdXjXOtIy7SYdf7pbxSWWVlqhnR/T2TpX6LX5NI62spt0a3ldIIEkPM6RHw==",
+      "version": "0.20.2",
+      "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.20.2.tgz",
+      "integrity": "sha512-d3qI41G4SuLiCGCFGUrKsSeTXyWG6yem1KcGZVS+3FYlYhtNoNgYrWcvkOoaqMhwXSMrZRl69ArHsGJ9mYdbbw==",
       "cpu": [
         "arm64"
       ],
@@ -910,9 +910,9 @@
       }
     },
     "node_modules/@esbuild/freebsd-x64": {
-      "version": "0.20.1",
-      "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.20.1.tgz",
-      "integrity": "sha512-itPwCw5C+Jh/c624vcDd9kRCCZVpzpQn8dtwoYIt2TJF3S9xJLiRohnnNrKwREvcZYx0n8sCSbvGH349XkcQeg==",
+      "version": "0.20.2",
+      "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.20.2.tgz",
+      "integrity": "sha512-d+DipyvHRuqEeM5zDivKV1KuXn9WeRX6vqSqIDgwIfPQtwMP4jaDsQsDncjTDDsExT4lR/91OLjRo8bmC1e+Cw==",
       "cpu": [
         "x64"
       ],
@@ -926,9 +926,9 @@
       }
     },
     "node_modules/@esbuild/linux-arm": {
-      "version": "0.20.1",
-      "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.20.1.tgz",
-      "integrity": "sha512-LojC28v3+IhIbfQ+Vu4Ut5n3wKcgTu6POKIHN9Wpt0HnfgUGlBuyDDQR4jWZUZFyYLiz4RBBBmfU6sNfn6RhLw==",
+      "version": "0.20.2",
+      "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.20.2.tgz",
+      "integrity": "sha512-VhLPeR8HTMPccbuWWcEUD1Az68TqaTYyj6nfE4QByZIQEQVWBB8vup8PpR7y1QHL3CpcF6xd5WVBU/+SBEvGTg==",
       "cpu": [
         "arm"
       ],
@@ -942,9 +942,9 @@
       }
     },
     "node_modules/@esbuild/linux-arm64": {
-      "version": "0.20.1",
-      "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.20.1.tgz",
-      "integrity": "sha512-cX8WdlF6Cnvw/DO9/X7XLH2J6CkBnz7Twjpk56cshk9sjYVcuh4sXQBy5bmTwzBjNVZze2yaV1vtcJS04LbN8w==",
+      "version": "0.20.2",
+      "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.20.2.tgz",
+      "integrity": "sha512-9pb6rBjGvTFNira2FLIWqDk/uaf42sSyLE8j1rnUpuzsODBq7FvpwHYZxQ/It/8b+QOS1RYfqgGFNLRI+qlq2A==",
       "cpu": [
         "arm64"
       ],
@@ -958,9 +958,9 @@
       }
     },
     "node_modules/@esbuild/linux-ia32": {
-      "version": "0.20.1",
-      "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.20.1.tgz",
-      "integrity": "sha512-4H/sQCy1mnnGkUt/xszaLlYJVTz3W9ep52xEefGtd6yXDQbz/5fZE5dFLUgsPdbUOQANcVUa5iO6g3nyy5BJiw==",
+      "version": "0.20.2",
+      "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.20.2.tgz",
+      "integrity": "sha512-o10utieEkNPFDZFQm9CoP7Tvb33UutoJqg3qKf1PWVeeJhJw0Q347PxMvBgVVFgouYLGIhFYG0UGdBumROyiig==",
       "cpu": [
         "ia32"
       ],
@@ -974,9 +974,9 @@
       }
     },
     "node_modules/@esbuild/linux-loong64": {
-      "version": "0.20.1",
-      "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.20.1.tgz",
-      "integrity": "sha512-c0jgtB+sRHCciVXlyjDcWb2FUuzlGVRwGXgI+3WqKOIuoo8AmZAddzeOHeYLtD+dmtHw3B4Xo9wAUdjlfW5yYA==",
+      "version": "0.20.2",
+      "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.20.2.tgz",
+      "integrity": "sha512-PR7sp6R/UC4CFVomVINKJ80pMFlfDfMQMYynX7t1tNTeivQ6XdX5r2XovMmha/VjR1YN/HgHWsVcTRIMkymrgQ==",
       "cpu": [
         "loong64"
       ],
@@ -990,9 +990,9 @@
       }
     },
     "node_modules/@esbuild/linux-mips64el": {
-      "version": "0.20.1",
-      "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.20.1.tgz",
-      "integrity": "sha512-TgFyCfIxSujyuqdZKDZ3yTwWiGv+KnlOeXXitCQ+trDODJ+ZtGOzLkSWngynP0HZnTsDyBbPy7GWVXWaEl6lhA==",
+      "version": "0.20.2",
+      "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.20.2.tgz",
+      "integrity": "sha512-4BlTqeutE/KnOiTG5Y6Sb/Hw6hsBOZapOVF6njAESHInhlQAghVVZL1ZpIctBOoTFbQyGW+LsVYZ8lSSB3wkjA==",
       "cpu": [
         "mips64el"
       ],
@@ -1006,9 +1006,9 @@
       }
     },
     "node_modules/@esbuild/linux-ppc64": {
-      "version": "0.20.1",
-      "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.20.1.tgz",
-      "integrity": "sha512-b+yuD1IUeL+Y93PmFZDZFIElwbmFfIKLKlYI8M6tRyzE6u7oEP7onGk0vZRh8wfVGC2dZoy0EqX1V8qok4qHaw==",
+      "version": "0.20.2",
+      "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.20.2.tgz",
+      "integrity": "sha512-rD3KsaDprDcfajSKdn25ooz5J5/fWBylaaXkuotBDGnMnDP1Uv5DLAN/45qfnf3JDYyJv/ytGHQaziHUdyzaAg==",
       "cpu": [
         "ppc64"
       ],
@@ -1022,9 +1022,9 @@
       }
     },
     "node_modules/@esbuild/linux-riscv64": {
-      "version": "0.20.1",
-      "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.20.1.tgz",
-      "integrity": "sha512-wpDlpE0oRKZwX+GfomcALcouqjjV8MIX8DyTrxfyCfXxoKQSDm45CZr9fanJ4F6ckD4yDEPT98SrjvLwIqUCgg==",
+      "version": "0.20.2",
+      "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.20.2.tgz",
+      "integrity": "sha512-snwmBKacKmwTMmhLlz/3aH1Q9T8v45bKYGE3j26TsaOVtjIag4wLfWSiZykXzXuE1kbCE+zJRmwp+ZbIHinnVg==",
       "cpu": [
         "riscv64"
       ],
@@ -1038,9 +1038,9 @@
       }
     },
     "node_modules/@esbuild/linux-s390x": {
-      "version": "0.20.1",
-      "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.20.1.tgz",
-      "integrity": "sha512-5BepC2Au80EohQ2dBpyTquqGCES7++p7G+7lXe1bAIvMdXm4YYcEfZtQrP4gaoZ96Wv1Ute61CEHFU7h4FMueQ==",
+      "version": "0.20.2",
+      "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.20.2.tgz",
+      "integrity": "sha512-wcWISOobRWNm3cezm5HOZcYz1sKoHLd8VL1dl309DiixxVFoFe/o8HnwuIwn6sXre88Nwj+VwZUvJf4AFxkyrQ==",
       "cpu": [
         "s390x"
       ],
@@ -1054,9 +1054,9 @@
       }
     },
     "node_modules/@esbuild/linux-x64": {
-      "version": "0.20.1",
-      "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.20.1.tgz",
-      "integrity": "sha512-5gRPk7pKuaIB+tmH+yKd2aQTRpqlf1E4f/mC+tawIm/CGJemZcHZpp2ic8oD83nKgUPMEd0fNanrnFljiruuyA==",
+      "version": "0.20.2",
+      "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.20.2.tgz",
+      "integrity": "sha512-1MdwI6OOTsfQfek8sLwgyjOXAu+wKhLEoaOLTjbijk6E2WONYpH9ZU2mNtR+lZ2B4uwr+usqGuVfFT9tMtGvGw==",
       "cpu": [
         "x64"
       ],
@@ -1070,9 +1070,9 @@
       }
     },
     "node_modules/@esbuild/netbsd-x64": {
-      "version": "0.20.1",
-      "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.20.1.tgz",
-      "integrity": "sha512-4fL68JdrLV2nVW2AaWZBv3XEm3Ae3NZn/7qy2KGAt3dexAgSVT+Hc97JKSZnqezgMlv9x6KV0ZkZY7UO5cNLCg==",
+      "version": "0.20.2",
+      "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.20.2.tgz",
+      "integrity": "sha512-K8/DhBxcVQkzYc43yJXDSyjlFeHQJBiowJ0uVL6Tor3jGQfSGHNNJcWxNbOI8v5k82prYqzPuwkzHt3J1T1iZQ==",
       "cpu": [
         "x64"
       ],
@@ -1086,9 +1086,9 @@
       }
     },
     "node_modules/@esbuild/openbsd-x64": {
-      "version": "0.20.1",
-      "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.20.1.tgz",
-      "integrity": "sha512-GhRuXlvRE+twf2ES+8REbeCb/zeikNqwD3+6S5y5/x+DYbAQUNl0HNBs4RQJqrechS4v4MruEr8ZtAin/hK5iw==",
+      "version": "0.20.2",
+      "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.20.2.tgz",
+      "integrity": "sha512-eMpKlV0SThJmmJgiVyN9jTPJ2VBPquf6Kt/nAoo6DgHAoN57K15ZghiHaMvqjCye/uU4X5u3YSMgVBI1h3vKrQ==",
       "cpu": [
         "x64"
       ],
@@ -1102,9 +1102,9 @@
       }
     },
     "node_modules/@esbuild/sunos-x64": {
-      "version": "0.20.1",
-      "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.20.1.tgz",
-      "integrity": "sha512-ZnWEyCM0G1Ex6JtsygvC3KUUrlDXqOihw8RicRuQAzw+c4f1D66YlPNNV3rkjVW90zXVsHwZYWbJh3v+oQFM9Q==",
+      "version": "0.20.2",
+      "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.20.2.tgz",
+      "integrity": "sha512-2UyFtRC6cXLyejf/YEld4Hajo7UHILetzE1vsRcGL3earZEW77JxrFjH4Ez2qaTiEfMgAXxfAZCm1fvM/G/o8w==",
       "cpu": [
         "x64"
       ],
@@ -1118,9 +1118,9 @@
       }
     },
     "node_modules/@esbuild/win32-arm64": {
-      "version": "0.20.1",
-      "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.20.1.tgz",
-      "integrity": "sha512-QZ6gXue0vVQY2Oon9WyLFCdSuYbXSoxaZrPuJ4c20j6ICedfsDilNPYfHLlMH7vGfU5DQR0czHLmJvH4Nzis/A==",
+      "version": "0.20.2",
+      "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.20.2.tgz",
+      "integrity": "sha512-GRibxoawM9ZCnDxnP3usoUDO9vUkpAxIIZ6GQI+IlVmr5kP3zUq+l17xELTHMWTWzjxa2guPNyrpq1GWmPvcGQ==",
       "cpu": [
         "arm64"
       ],
@@ -1134,9 +1134,9 @@
       }
     },
     "node_modules/@esbuild/win32-ia32": {
-      "version": "0.20.1",
-      "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.20.1.tgz",
-      "integrity": "sha512-HzcJa1NcSWTAU0MJIxOho8JftNp9YALui3o+Ny7hCh0v5f90nprly1U3Sj1Ldj/CvKKdvvFsCRvDkpsEMp4DNw==",
+      "version": "0.20.2",
+      "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.20.2.tgz",
+      "integrity": "sha512-HfLOfn9YWmkSKRQqovpnITazdtquEW8/SoHW7pWpuEeguaZI4QnCRW6b+oZTztdBnZOS2hqJ6im/D5cPzBTTlQ==",
       "cpu": [
         "ia32"
       ],
@@ -1150,9 +1150,9 @@
       }
     },
     "node_modules/@esbuild/win32-x64": {
-      "version": "0.20.1",
-      "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.20.1.tgz",
-      "integrity": "sha512-0MBh53o6XtI6ctDnRMeQ+xoCN8kD2qI1rY1KgF/xdWQwoFeKou7puvDfV8/Wv4Ctx2rRpET/gGdz3YlNtNACSA==",
+      "version": "0.20.2",
+      "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.20.2.tgz",
+      "integrity": "sha512-N49X4lJX27+l9jbLKSqZ6bKNjzQvHaT8IIFUy+YIqmXQdjYCToGWwOItDrfby14c78aDd5NHQl29xingXfCdLQ==",
       "cpu": [
         "x64"
       ],
@@ -2130,15 +2130,6 @@
         "node": ">= 8"
       }
     },
-    "node_modules/data-uri-to-buffer": {
-      "version": "4.0.0",
-      "resolved": "https://registry.npmjs.org/data-uri-to-buffer/-/data-uri-to-buffer-4.0.0.tgz",
-      "integrity": "sha512-Vr3mLBA8qWmcuschSLAOogKgQ/Jwxulv3RNE4FXnYWRGujzrRWQI4m12fQqRkwX06C0KanhLr4hK+GydchZsaA==",
-      "dev": true,
-      "engines": {
-        "node": ">= 12"
-      }
-    },
     "node_modules/date-format": {
       "version": "4.0.14",
       "resolved": "https://registry.npmjs.org/date-format/-/date-format-4.0.14.tgz",
@@ -2677,9 +2668,9 @@
       }
     },
     "node_modules/esbuild": {
-      "version": "0.20.1",
-      "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.20.1.tgz",
-      "integrity": "sha512-OJwEgrpWm/PCMsLVWXKqvcjme3bHNpOgN7Tb6cQnR5n0TPbQx1/Xrn7rqM+wn17bYeT6MGB5sn1Bh5YiGi70nA==",
+      "version": "0.20.2",
+      "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.20.2.tgz",
+      "integrity": "sha512-WdOOppmUNU+IbZ0PaDiTst80zjnrOkyJNHoKupIcVyU8Lvla3Ugx94VzkQ32Ijqd7UhHJy75gNWDMUekcrSJ6g==",
       "dev": true,
       "hasInstallScript": true,
       "bin": {
@@ -2689,29 +2680,29 @@
         "node": ">=12"
       },
       "optionalDependencies": {
-        "@esbuild/aix-ppc64": "0.20.1",
-        "@esbuild/android-arm": "0.20.1",
-        "@esbuild/android-arm64": "0.20.1",
-        "@esbuild/android-x64": "0.20.1",
-        "@esbuild/darwin-arm64": "0.20.1",
-        "@esbuild/darwin-x64": "0.20.1",
-        "@esbuild/freebsd-arm64": "0.20.1",
-        "@esbuild/freebsd-x64": "0.20.1",
-        "@esbuild/linux-arm": "0.20.1",
-        "@esbuild/linux-arm64": "0.20.1",
-        "@esbuild/linux-ia32": "0.20.1",
-        "@esbuild/linux-loong64": "0.20.1",
-        "@esbuild/linux-mips64el": "0.20.1",
-        "@esbuild/linux-ppc64": "0.20.1",
-        "@esbuild/linux-riscv64": "0.20.1",
-        "@esbuild/linux-s390x": "0.20.1",
-        "@esbuild/linux-x64": "0.20.1",
-        "@esbuild/netbsd-x64": "0.20.1",
-        "@esbuild/openbsd-x64": "0.20.1",
-        "@esbuild/sunos-x64": "0.20.1",
-        "@esbuild/win32-arm64": "0.20.1",
-        "@esbuild/win32-ia32": "0.20.1",
-        "@esbuild/win32-x64": "0.20.1"
+        "@esbuild/aix-ppc64": "0.20.2",
+        "@esbuild/android-arm": "0.20.2",
+        "@esbuild/android-arm64": "0.20.2",
+        "@esbuild/android-x64": "0.20.2",
+        "@esbuild/darwin-arm64": "0.20.2",
+        "@esbuild/darwin-x64": "0.20.2",
+        "@esbuild/freebsd-arm64": "0.20.2",
+        "@esbuild/freebsd-x64": "0.20.2",
+        "@esbuild/linux-arm": "0.20.2",
+        "@esbuild/linux-arm64": "0.20.2",
+        "@esbuild/linux-ia32": "0.20.2",
+        "@esbuild/linux-loong64": "0.20.2",
+        "@esbuild/linux-mips64el": "0.20.2",
+        "@esbuild/linux-ppc64": "0.20.2",
+        "@esbuild/linux-riscv64": "0.20.2",
+        "@esbuild/linux-s390x": "0.20.2",
+        "@esbuild/linux-x64": "0.20.2",
+        "@esbuild/netbsd-x64": "0.20.2",
+        "@esbuild/openbsd-x64": "0.20.2",
+        "@esbuild/sunos-x64": "0.20.2",
+        "@esbuild/win32-arm64": "0.20.2",
+        "@esbuild/win32-ia32": "0.20.2",
+        "@esbuild/win32-x64": "0.20.2"
       }
     },
     "node_modules/esbuild-node-externals": {
@@ -2731,9 +2722,9 @@
       }
     },
     "node_modules/esbuild-plugin-entry-chunks": {
-      "version": "0.1.8",
-      "resolved": "https://registry.npmjs.org/esbuild-plugin-entry-chunks/-/esbuild-plugin-entry-chunks-0.1.8.tgz",
-      "integrity": "sha512-iKX18Uj8WTiRygwOGNa4S66pvNeexcvH1ohs/P5wV0fVGCRRzHzCiyI1/HShCVkC8HOnxvGWiG006PmsBHmS9Q==",
+      "version": "0.1.11",
+      "resolved": "https://registry.npmjs.org/esbuild-plugin-entry-chunks/-/esbuild-plugin-entry-chunks-0.1.11.tgz",
+      "integrity": "sha512-lSFwPa7YYdp0iSg3ukKKlHrJ735WpsqlkfsYzUHXYhFYRHPuYaf5qkNyWulyDL7ycPlguCo/Q4ALCsi1mu6waA==",
       "dev": true,
       "dependencies": {
         "depseek": "0.4.0"
@@ -3091,29 +3082,6 @@
         "reusify": "^1.0.4"
       }
     },
-    "node_modules/fetch-blob": {
-      "version": "3.2.0",
-      "resolved": "https://registry.npmjs.org/fetch-blob/-/fetch-blob-3.2.0.tgz",
-      "integrity": "sha512-7yAQpD2UMJzLi1Dqv7qFYnPbaPx7ZfFK6PiIxQ4PfkGPyNyl2Ugx+a/umUonmKqjhM4DnfbMvdX6otXq83soQQ==",
-      "dev": true,
-      "funding": [
-        {
-          "type": "github",
-          "url": "https://github.com/sponsors/jimmywarting"
-        },
-        {
-          "type": "paypal",
-          "url": "https://paypal.me/jimmywarting"
-        }
-      ],
-      "dependencies": {
-        "node-domexception": "^1.0.0",
-        "web-streams-polyfill": "^3.0.3"
-      },
-      "engines": {
-        "node": "^12.20 || >= 14.13"
-      }
-    },
     "node_modules/figures": {
       "version": "5.0.0",
       "resolved": "https://registry.npmjs.org/figures/-/figures-5.0.0.tgz",
@@ -3242,18 +3210,6 @@
         "node": ">=8.0.0"
       }
     },
-    "node_modules/formdata-polyfill": {
-      "version": "4.0.10",
-      "resolved": "https://registry.npmjs.org/formdata-polyfill/-/formdata-polyfill-4.0.10.tgz",
-      "integrity": "sha512-buewHzMvYL29jdeQTVILecSaZKnt/RJWjoZCF5OW60Z67/GmSLBkOFM7qh1PI3zFNtJbaZL5eQu1vLfazOwj4g==",
-      "dev": true,
-      "dependencies": {
-        "fetch-blob": "^3.1.2"
-      },
-      "engines": {
-        "node": ">=12.20.0"
-      }
-    },
     "node_modules/from": {
       "version": "0.1.7",
       "resolved": "https://registry.npmjs.org/from/-/from-0.1.7.tgz",
@@ -4658,43 +4614,6 @@
         "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1"
       }
     },
-    "node_modules/node-domexception": {
-      "version": "1.0.0",
-      "resolved": "https://registry.npmjs.org/node-domexception/-/node-domexception-1.0.0.tgz",
-      "integrity": "sha512-/jKZoMpw0F8GRwl4/eLROPA3cfcXtLApP0QzLmUT/HuPCZWyB7IY9ZrMeKw2O/nFIqPQB3PVM9aYm0F312AXDQ==",
-      "dev": true,
-      "funding": [
-        {
-          "type": "github",
-          "url": "https://github.com/sponsors/jimmywarting"
-        },
-        {
-          "type": "github",
-          "url": "https://paypal.me/jimmywarting"
-        }
-      ],
-      "engines": {
-        "node": ">=10.5.0"
-      }
-    },
-    "node_modules/node-fetch": {
-      "version": "3.3.2",
-      "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-3.3.2.tgz",
-      "integrity": "sha512-dRB78srN/l6gqWulah9SrxeYnxeddIG30+GOqK/9OlLVyLg3HPnr6SqOWTWOXKRwC2eGYCkZ59NNuSgvSrpgOA==",
-      "dev": true,
-      "dependencies": {
-        "data-uri-to-buffer": "^4.0.0",
-        "fetch-blob": "^3.1.4",
-        "formdata-polyfill": "^4.0.10"
-      },
-      "engines": {
-        "node": "^12.20.0 || ^14.13.1 || >=16.0.0"
-      },
-      "funding": {
-        "type": "opencollective",
-        "url": "https://opencollective.com/node-fetch"
-      }
-    },
     "node_modules/node-fetch-native": {
       "version": "1.6.2",
       "resolved": "https://registry.npmjs.org/node-fetch-native/-/node-fetch-native-1.6.2.tgz",
@@ -6758,15 +6677,6 @@
       "integrity": "sha512-V8X6hPIzY1juvrSVREmtRhK9AHn/8c2z8XxaibESU+jyG/RinZ9x9x6aw8qEuFAi7R6Kl/EWGbU2Yq/9u6TTjw==",
       "dev": true
     },
-    "node_modules/web-streams-polyfill": {
-      "version": "3.2.1",
-      "resolved": "https://registry.npmjs.org/web-streams-polyfill/-/web-streams-polyfill-3.2.1.tgz",
-      "integrity": "sha512-e0MO3wdXWKrLbL0DgGnUV7WHVuw9OUvL4hjgnPkIeEvESk74gAITi5G606JtZPp39cd8HA9VQzCIvA49LpPN5Q==",
-      "dev": true,
-      "engines": {
-        "node": ">= 8"
-      }
-    },
     "node_modules/webpod": {
       "version": "0.0.2",
       "resolved": "https://registry.npmjs.org/webpod/-/webpod-0.0.2.tgz",
@@ -6926,6 +6836,12 @@
       "funding": {
         "url": "https://github.com/sponsors/sindresorhus"
       }
+    },
+    "node_modules/zurk": {
+      "version": "0.0.27",
+      "resolved": "https://registry.npmjs.org/zurk/-/zurk-0.0.27.tgz",
+      "integrity": "sha512-BwvvxnPmiiI0H8ThWj7XSUrMN33X/JTb+qiA7/2M03jwwFtCGPwDxpNzKbI9aNKRkJu1v6XD73Y5aYY+eNyGSg==",
+      "dev": true
     }
   },
   "dependencies": {
@@ -7486,163 +7402,163 @@
       "dev": true
     },
     "@esbuild/aix-ppc64": {
-      "version": "0.20.1",
-      "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.20.1.tgz",
-      "integrity": "sha512-m55cpeupQ2DbuRGQMMZDzbv9J9PgVelPjlcmM5kxHnrBdBx6REaEd7LamYV7Dm8N7rCyR/XwU6rVP8ploKtIkA==",
+      "version": "0.20.2",
+      "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.20.2.tgz",
+      "integrity": "sha512-D+EBOJHXdNZcLJRBkhENNG8Wji2kgc9AZ9KiPr1JuZjsNtyHzrsfLRrY0tk2H2aoFu6RANO1y1iPPUCDYWkb5g==",
       "dev": true,
       "optional": true
     },
     "@esbuild/android-arm": {
-      "version": "0.20.1",
-      "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.20.1.tgz",
-      "integrity": "sha512-4j0+G27/2ZXGWR5okcJi7pQYhmkVgb4D7UKwxcqrjhvp5TKWx3cUjgB1CGj1mfdmJBQ9VnUGgUhign+FPF2Zgw==",
+      "version": "0.20.2",
+      "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.20.2.tgz",
+      "integrity": "sha512-t98Ra6pw2VaDhqNWO2Oph2LXbz/EJcnLmKLGBJwEwXX/JAN83Fym1rU8l0JUWK6HkIbWONCSSatf4sf2NBRx/w==",
       "dev": true,
       "optional": true
     },
     "@esbuild/android-arm64": {
-      "version": "0.20.1",
-      "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.20.1.tgz",
-      "integrity": "sha512-hCnXNF0HM6AjowP+Zou0ZJMWWa1VkD77BXe959zERgGJBBxB+sV+J9f/rcjeg2c5bsukD/n17RKWXGFCO5dD5A==",
+      "version": "0.20.2",
+      "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.20.2.tgz",
+      "integrity": "sha512-mRzjLacRtl/tWU0SvD8lUEwb61yP9cqQo6noDZP/O8VkwafSYwZ4yWy24kan8jE/IMERpYncRt2dw438LP3Xmg==",
       "dev": true,
       "optional": true
     },
     "@esbuild/android-x64": {
-      "version": "0.20.1",
-      "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.20.1.tgz",
-      "integrity": "sha512-MSfZMBoAsnhpS+2yMFYIQUPs8Z19ajwfuaSZx+tSl09xrHZCjbeXXMsUF/0oq7ojxYEpsSo4c0SfjxOYXRbpaA==",
+      "version": "0.20.2",
+      "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.20.2.tgz",
+      "integrity": "sha512-btzExgV+/lMGDDa194CcUQm53ncxzeBrWJcncOBxuC6ndBkKxnHdFJn86mCIgTELsooUmwUm9FkhSp5HYu00Rg==",
       "dev": true,
       "optional": true
     },
     "@esbuild/darwin-arm64": {
-      "version": "0.20.1",
-      "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.20.1.tgz",
-      "integrity": "sha512-Ylk6rzgMD8klUklGPzS414UQLa5NPXZD5tf8JmQU8GQrj6BrFA/Ic9tb2zRe1kOZyCbGl+e8VMbDRazCEBqPvA==",
+      "version": "0.20.2",
+      "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.20.2.tgz",
+      "integrity": "sha512-4J6IRT+10J3aJH3l1yzEg9y3wkTDgDk7TSDFX+wKFiWjqWp/iCfLIYzGyasx9l0SAFPT1HwSCR+0w/h1ES/MjA==",
       "dev": true,
       "optional": true
     },
     "@esbuild/darwin-x64": {
-      "version": "0.20.1",
-      "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.20.1.tgz",
-      "integrity": "sha512-pFIfj7U2w5sMp52wTY1XVOdoxw+GDwy9FsK3OFz4BpMAjvZVs0dT1VXs8aQm22nhwoIWUmIRaE+4xow8xfIDZA==",
+      "version": "0.20.2",
+      "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.20.2.tgz",
+      "integrity": "sha512-tBcXp9KNphnNH0dfhv8KYkZhjc+H3XBkF5DKtswJblV7KlT9EI2+jeA8DgBjp908WEuYll6pF+UStUCfEpdysA==",
       "dev": true,
       "optional": true
     },
     "@esbuild/freebsd-arm64": {
-      "version": "0.20.1",
-      "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.20.1.tgz",
-      "integrity": "sha512-UyW1WZvHDuM4xDz0jWun4qtQFauNdXjXOtIy7SYdf7pbxSWWVlqhnR/T2TpX6LX5NI62spt0a3ldIIEkPM6RHw==",
+      "version": "0.20.2",
+      "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.20.2.tgz",
+      "integrity": "sha512-d3qI41G4SuLiCGCFGUrKsSeTXyWG6yem1KcGZVS+3FYlYhtNoNgYrWcvkOoaqMhwXSMrZRl69ArHsGJ9mYdbbw==",
       "dev": true,
       "optional": true
     },
     "@esbuild/freebsd-x64": {
-      "version": "0.20.1",
-      "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.20.1.tgz",
-      "integrity": "sha512-itPwCw5C+Jh/c624vcDd9kRCCZVpzpQn8dtwoYIt2TJF3S9xJLiRohnnNrKwREvcZYx0n8sCSbvGH349XkcQeg==",
+      "version": "0.20.2",
+      "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.20.2.tgz",
+      "integrity": "sha512-d+DipyvHRuqEeM5zDivKV1KuXn9WeRX6vqSqIDgwIfPQtwMP4jaDsQsDncjTDDsExT4lR/91OLjRo8bmC1e+Cw==",
       "dev": true,
       "optional": true
     },
     "@esbuild/linux-arm": {
-      "version": "0.20.1",
-      "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.20.1.tgz",
-      "integrity": "sha512-LojC28v3+IhIbfQ+Vu4Ut5n3wKcgTu6POKIHN9Wpt0HnfgUGlBuyDDQR4jWZUZFyYLiz4RBBBmfU6sNfn6RhLw==",
+      "version": "0.20.2",
+      "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.20.2.tgz",
+      "integrity": "sha512-VhLPeR8HTMPccbuWWcEUD1Az68TqaTYyj6nfE4QByZIQEQVWBB8vup8PpR7y1QHL3CpcF6xd5WVBU/+SBEvGTg==",
       "dev": true,
       "optional": true
     },
     "@esbuild/linux-arm64": {
-      "version": "0.20.1",
-      "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.20.1.tgz",
-      "integrity": "sha512-cX8WdlF6Cnvw/DO9/X7XLH2J6CkBnz7Twjpk56cshk9sjYVcuh4sXQBy5bmTwzBjNVZze2yaV1vtcJS04LbN8w==",
+      "version": "0.20.2",
+      "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.20.2.tgz",
+      "integrity": "sha512-9pb6rBjGvTFNira2FLIWqDk/uaf42sSyLE8j1rnUpuzsODBq7FvpwHYZxQ/It/8b+QOS1RYfqgGFNLRI+qlq2A==",
       "dev": true,
       "optional": true
     },
     "@esbuild/linux-ia32": {
-      "version": "0.20.1",
-      "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.20.1.tgz",
-      "integrity": "sha512-4H/sQCy1mnnGkUt/xszaLlYJVTz3W9ep52xEefGtd6yXDQbz/5fZE5dFLUgsPdbUOQANcVUa5iO6g3nyy5BJiw==",
+      "version": "0.20.2",
+      "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.20.2.tgz",
+      "integrity": "sha512-o10utieEkNPFDZFQm9CoP7Tvb33UutoJqg3qKf1PWVeeJhJw0Q347PxMvBgVVFgouYLGIhFYG0UGdBumROyiig==",
       "dev": true,
       "optional": true
     },
     "@esbuild/linux-loong64": {
-      "version": "0.20.1",
-      "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.20.1.tgz",
-      "integrity": "sha512-c0jgtB+sRHCciVXlyjDcWb2FUuzlGVRwGXgI+3WqKOIuoo8AmZAddzeOHeYLtD+dmtHw3B4Xo9wAUdjlfW5yYA==",
+      "version": "0.20.2",
+      "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.20.2.tgz",
+      "integrity": "sha512-PR7sp6R/UC4CFVomVINKJ80pMFlfDfMQMYynX7t1tNTeivQ6XdX5r2XovMmha/VjR1YN/HgHWsVcTRIMkymrgQ==",
       "dev": true,
       "optional": true
     },
     "@esbuild/linux-mips64el": {
-      "version": "0.20.1",
-      "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.20.1.tgz",
-      "integrity": "sha512-TgFyCfIxSujyuqdZKDZ3yTwWiGv+KnlOeXXitCQ+trDODJ+ZtGOzLkSWngynP0HZnTsDyBbPy7GWVXWaEl6lhA==",
+      "version": "0.20.2",
+      "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.20.2.tgz",
+      "integrity": "sha512-4BlTqeutE/KnOiTG5Y6Sb/Hw6hsBOZapOVF6njAESHInhlQAghVVZL1ZpIctBOoTFbQyGW+LsVYZ8lSSB3wkjA==",
       "dev": true,
       "optional": true
     },
     "@esbuild/linux-ppc64": {
-      "version": "0.20.1",
-      "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.20.1.tgz",
-      "integrity": "sha512-b+yuD1IUeL+Y93PmFZDZFIElwbmFfIKLKlYI8M6tRyzE6u7oEP7onGk0vZRh8wfVGC2dZoy0EqX1V8qok4qHaw==",
+      "version": "0.20.2",
+      "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.20.2.tgz",
+      "integrity": "sha512-rD3KsaDprDcfajSKdn25ooz5J5/fWBylaaXkuotBDGnMnDP1Uv5DLAN/45qfnf3JDYyJv/ytGHQaziHUdyzaAg==",
       "dev": true,
       "optional": true
     },
     "@esbuild/linux-riscv64": {
-      "version": "0.20.1",
-      "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.20.1.tgz",
-      "integrity": "sha512-wpDlpE0oRKZwX+GfomcALcouqjjV8MIX8DyTrxfyCfXxoKQSDm45CZr9fanJ4F6ckD4yDEPT98SrjvLwIqUCgg==",
+      "version": "0.20.2",
+      "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.20.2.tgz",
+      "integrity": "sha512-snwmBKacKmwTMmhLlz/3aH1Q9T8v45bKYGE3j26TsaOVtjIag4wLfWSiZykXzXuE1kbCE+zJRmwp+ZbIHinnVg==",
       "dev": true,
       "optional": true
     },
     "@esbuild/linux-s390x": {
-      "version": "0.20.1",
-      "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.20.1.tgz",
-      "integrity": "sha512-5BepC2Au80EohQ2dBpyTquqGCES7++p7G+7lXe1bAIvMdXm4YYcEfZtQrP4gaoZ96Wv1Ute61CEHFU7h4FMueQ==",
+      "version": "0.20.2",
+      "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.20.2.tgz",
+      "integrity": "sha512-wcWISOobRWNm3cezm5HOZcYz1sKoHLd8VL1dl309DiixxVFoFe/o8HnwuIwn6sXre88Nwj+VwZUvJf4AFxkyrQ==",
       "dev": true,
       "optional": true
     },
     "@esbuild/linux-x64": {
-      "version": "0.20.1",
-      "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.20.1.tgz",
-      "integrity": "sha512-5gRPk7pKuaIB+tmH+yKd2aQTRpqlf1E4f/mC+tawIm/CGJemZcHZpp2ic8oD83nKgUPMEd0fNanrnFljiruuyA==",
+      "version": "0.20.2",
+      "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.20.2.tgz",
+      "integrity": "sha512-1MdwI6OOTsfQfek8sLwgyjOXAu+wKhLEoaOLTjbijk6E2WONYpH9ZU2mNtR+lZ2B4uwr+usqGuVfFT9tMtGvGw==",
       "dev": true,
       "optional": true
     },
     "@esbuild/netbsd-x64": {
-      "version": "0.20.1",
-      "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.20.1.tgz",
-      "integrity": "sha512-4fL68JdrLV2nVW2AaWZBv3XEm3Ae3NZn/7qy2KGAt3dexAgSVT+Hc97JKSZnqezgMlv9x6KV0ZkZY7UO5cNLCg==",
+      "version": "0.20.2",
+      "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.20.2.tgz",
+      "integrity": "sha512-K8/DhBxcVQkzYc43yJXDSyjlFeHQJBiowJ0uVL6Tor3jGQfSGHNNJcWxNbOI8v5k82prYqzPuwkzHt3J1T1iZQ==",
       "dev": true,
       "optional": true
     },
     "@esbuild/openbsd-x64": {
-      "version": "0.20.1",
-      "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.20.1.tgz",
-      "integrity": "sha512-GhRuXlvRE+twf2ES+8REbeCb/zeikNqwD3+6S5y5/x+DYbAQUNl0HNBs4RQJqrechS4v4MruEr8ZtAin/hK5iw==",
+      "version": "0.20.2",
+      "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.20.2.tgz",
+      "integrity": "sha512-eMpKlV0SThJmmJgiVyN9jTPJ2VBPquf6Kt/nAoo6DgHAoN57K15ZghiHaMvqjCye/uU4X5u3YSMgVBI1h3vKrQ==",
       "dev": true,
       "optional": true
     },
     "@esbuild/sunos-x64": {
-      "version": "0.20.1",
-      "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.20.1.tgz",
-      "integrity": "sha512-ZnWEyCM0G1Ex6JtsygvC3KUUrlDXqOihw8RicRuQAzw+c4f1D66YlPNNV3rkjVW90zXVsHwZYWbJh3v+oQFM9Q==",
+      "version": "0.20.2",
+      "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.20.2.tgz",
+      "integrity": "sha512-2UyFtRC6cXLyejf/YEld4Hajo7UHILetzE1vsRcGL3earZEW77JxrFjH4Ez2qaTiEfMgAXxfAZCm1fvM/G/o8w==",
       "dev": true,
       "optional": true
     },
     "@esbuild/win32-arm64": {
-      "version": "0.20.1",
-      "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.20.1.tgz",
-      "integrity": "sha512-QZ6gXue0vVQY2Oon9WyLFCdSuYbXSoxaZrPuJ4c20j6ICedfsDilNPYfHLlMH7vGfU5DQR0czHLmJvH4Nzis/A==",
+      "version": "0.20.2",
+      "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.20.2.tgz",
+      "integrity": "sha512-GRibxoawM9ZCnDxnP3usoUDO9vUkpAxIIZ6GQI+IlVmr5kP3zUq+l17xELTHMWTWzjxa2guPNyrpq1GWmPvcGQ==",
       "dev": true,
       "optional": true
     },
     "@esbuild/win32-ia32": {
-      "version": "0.20.1",
-      "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.20.1.tgz",
-      "integrity": "sha512-HzcJa1NcSWTAU0MJIxOho8JftNp9YALui3o+Ny7hCh0v5f90nprly1U3Sj1Ldj/CvKKdvvFsCRvDkpsEMp4DNw==",
+      "version": "0.20.2",
+      "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.20.2.tgz",
+      "integrity": "sha512-HfLOfn9YWmkSKRQqovpnITazdtquEW8/SoHW7pWpuEeguaZI4QnCRW6b+oZTztdBnZOS2hqJ6im/D5cPzBTTlQ==",
       "dev": true,
       "optional": true
     },
     "@esbuild/win32-x64": {
-      "version": "0.20.1",
-      "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.20.1.tgz",
-      "integrity": "sha512-0MBh53o6XtI6ctDnRMeQ+xoCN8kD2qI1rY1KgF/xdWQwoFeKou7puvDfV8/Wv4Ctx2rRpET/gGdz3YlNtNACSA==",
+      "version": "0.20.2",
+      "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.20.2.tgz",
+      "integrity": "sha512-N49X4lJX27+l9jbLKSqZ6bKNjzQvHaT8IIFUy+YIqmXQdjYCToGWwOItDrfby14c78aDd5NHQl29xingXfCdLQ==",
       "dev": true,
       "optional": true
     },
@@ -8356,12 +8272,6 @@
         }
       }
     },
-    "data-uri-to-buffer": {
-      "version": "4.0.0",
-      "resolved": "https://registry.npmjs.org/data-uri-to-buffer/-/data-uri-to-buffer-4.0.0.tgz",
-      "integrity": "sha512-Vr3mLBA8qWmcuschSLAOogKgQ/Jwxulv3RNE4FXnYWRGujzrRWQI4m12fQqRkwX06C0KanhLr4hK+GydchZsaA==",
-      "dev": true
-    },
     "date-format": {
       "version": "4.0.14",
       "resolved": "https://registry.npmjs.org/date-format/-/date-format-4.0.14.tgz",
@@ -8773,34 +8683,34 @@
       }
     },
     "esbuild": {
-      "version": "0.20.1",
-      "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.20.1.tgz",
-      "integrity": "sha512-OJwEgrpWm/PCMsLVWXKqvcjme3bHNpOgN7Tb6cQnR5n0TPbQx1/Xrn7rqM+wn17bYeT6MGB5sn1Bh5YiGi70nA==",
-      "dev": true,
-      "requires": {
-        "@esbuild/aix-ppc64": "0.20.1",
-        "@esbuild/android-arm": "0.20.1",
-        "@esbuild/android-arm64": "0.20.1",
-        "@esbuild/android-x64": "0.20.1",
-        "@esbuild/darwin-arm64": "0.20.1",
-        "@esbuild/darwin-x64": "0.20.1",
-        "@esbuild/freebsd-arm64": "0.20.1",
-        "@esbuild/freebsd-x64": "0.20.1",
-        "@esbuild/linux-arm": "0.20.1",
-        "@esbuild/linux-arm64": "0.20.1",
-        "@esbuild/linux-ia32": "0.20.1",
-        "@esbuild/linux-loong64": "0.20.1",
-        "@esbuild/linux-mips64el": "0.20.1",
-        "@esbuild/linux-ppc64": "0.20.1",
-        "@esbuild/linux-riscv64": "0.20.1",
-        "@esbuild/linux-s390x": "0.20.1",
-        "@esbuild/linux-x64": "0.20.1",
-        "@esbuild/netbsd-x64": "0.20.1",
-        "@esbuild/openbsd-x64": "0.20.1",
-        "@esbuild/sunos-x64": "0.20.1",
-        "@esbuild/win32-arm64": "0.20.1",
-        "@esbuild/win32-ia32": "0.20.1",
-        "@esbuild/win32-x64": "0.20.1"
+      "version": "0.20.2",
+      "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.20.2.tgz",
+      "integrity": "sha512-WdOOppmUNU+IbZ0PaDiTst80zjnrOkyJNHoKupIcVyU8Lvla3Ugx94VzkQ32Ijqd7UhHJy75gNWDMUekcrSJ6g==",
+      "dev": true,
+      "requires": {
+        "@esbuild/aix-ppc64": "0.20.2",
+        "@esbuild/android-arm": "0.20.2",
+        "@esbuild/android-arm64": "0.20.2",
+        "@esbuild/android-x64": "0.20.2",
+        "@esbuild/darwin-arm64": "0.20.2",
+        "@esbuild/darwin-x64": "0.20.2",
+        "@esbuild/freebsd-arm64": "0.20.2",
+        "@esbuild/freebsd-x64": "0.20.2",
+        "@esbuild/linux-arm": "0.20.2",
+        "@esbuild/linux-arm64": "0.20.2",
+        "@esbuild/linux-ia32": "0.20.2",
+        "@esbuild/linux-loong64": "0.20.2",
+        "@esbuild/linux-mips64el": "0.20.2",
+        "@esbuild/linux-ppc64": "0.20.2",
+        "@esbuild/linux-riscv64": "0.20.2",
+        "@esbuild/linux-s390x": "0.20.2",
+        "@esbuild/linux-x64": "0.20.2",
+        "@esbuild/netbsd-x64": "0.20.2",
+        "@esbuild/openbsd-x64": "0.20.2",
+        "@esbuild/sunos-x64": "0.20.2",
+        "@esbuild/win32-arm64": "0.20.2",
+        "@esbuild/win32-ia32": "0.20.2",
+        "@esbuild/win32-x64": "0.20.2"
       }
     },
     "esbuild-node-externals": {
@@ -8814,9 +8724,9 @@
       }
     },
     "esbuild-plugin-entry-chunks": {
-      "version": "0.1.8",
-      "resolved": "https://registry.npmjs.org/esbuild-plugin-entry-chunks/-/esbuild-plugin-entry-chunks-0.1.8.tgz",
-      "integrity": "sha512-iKX18Uj8WTiRygwOGNa4S66pvNeexcvH1ohs/P5wV0fVGCRRzHzCiyI1/HShCVkC8HOnxvGWiG006PmsBHmS9Q==",
+      "version": "0.1.11",
+      "resolved": "https://registry.npmjs.org/esbuild-plugin-entry-chunks/-/esbuild-plugin-entry-chunks-0.1.11.tgz",
+      "integrity": "sha512-lSFwPa7YYdp0iSg3ukKKlHrJ735WpsqlkfsYzUHXYhFYRHPuYaf5qkNyWulyDL7ycPlguCo/Q4ALCsi1mu6waA==",
       "dev": true,
       "requires": {
         "depseek": "0.4.0"
@@ -9072,16 +8982,6 @@
         "reusify": "^1.0.4"
       }
     },
-    "fetch-blob": {
-      "version": "3.2.0",
-      "resolved": "https://registry.npmjs.org/fetch-blob/-/fetch-blob-3.2.0.tgz",
-      "integrity": "sha512-7yAQpD2UMJzLi1Dqv7qFYnPbaPx7ZfFK6PiIxQ4PfkGPyNyl2Ugx+a/umUonmKqjhM4DnfbMvdX6otXq83soQQ==",
-      "dev": true,
-      "requires": {
-        "node-domexception": "^1.0.0",
-        "web-streams-polyfill": "^3.0.3"
-      }
-    },
     "figures": {
       "version": "5.0.0",
       "resolved": "https://registry.npmjs.org/figures/-/figures-5.0.0.tgz",
@@ -9174,15 +9074,6 @@
         "signal-exit": "^3.0.2"
       }
     },
-    "formdata-polyfill": {
-      "version": "4.0.10",
-      "resolved": "https://registry.npmjs.org/formdata-polyfill/-/formdata-polyfill-4.0.10.tgz",
-      "integrity": "sha512-buewHzMvYL29jdeQTVILecSaZKnt/RJWjoZCF5OW60Z67/GmSLBkOFM7qh1PI3zFNtJbaZL5eQu1vLfazOwj4g==",
-      "dev": true,
-      "requires": {
-        "fetch-blob": "^3.1.2"
-      }
-    },
     "from": {
       "version": "0.1.7",
       "resolved": "https://registry.npmjs.org/from/-/from-0.1.7.tgz",
@@ -10186,23 +10077,6 @@
       "integrity": "sha512-eSRppjcPIatRIMC1U6UngP8XFcz8MQWGQdt1MTBQ7NaAmvXDfvNxbvWV3x2y6CdEUciCSsDHDQZbhYaB8QEo2g==",
       "dev": true
     },
-    "node-domexception": {
-      "version": "1.0.0",
-      "resolved": "https://registry.npmjs.org/node-domexception/-/node-domexception-1.0.0.tgz",
-      "integrity": "sha512-/jKZoMpw0F8GRwl4/eLROPA3cfcXtLApP0QzLmUT/HuPCZWyB7IY9ZrMeKw2O/nFIqPQB3PVM9aYm0F312AXDQ==",
-      "dev": true
-    },
-    "node-fetch": {
-      "version": "3.3.2",
-      "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-3.3.2.tgz",
-      "integrity": "sha512-dRB78srN/l6gqWulah9SrxeYnxeddIG30+GOqK/9OlLVyLg3HPnr6SqOWTWOXKRwC2eGYCkZ59NNuSgvSrpgOA==",
-      "dev": true,
-      "requires": {
-        "data-uri-to-buffer": "^4.0.0",
-        "fetch-blob": "^3.1.4",
-        "formdata-polyfill": "^4.0.10"
-      }
-    },
     "node-fetch-native": {
       "version": "1.6.2",
       "resolved": "https://registry.npmjs.org/node-fetch-native/-/node-fetch-native-1.6.2.tgz",
@@ -11686,12 +11560,6 @@
       "integrity": "sha512-V8X6hPIzY1juvrSVREmtRhK9AHn/8c2z8XxaibESU+jyG/RinZ9x9x6aw8qEuFAi7R6Kl/EWGbU2Yq/9u6TTjw==",
       "dev": true
     },
-    "web-streams-polyfill": {
-      "version": "3.2.1",
-      "resolved": "https://registry.npmjs.org/web-streams-polyfill/-/web-streams-polyfill-3.2.1.tgz",
-      "integrity": "sha512-e0MO3wdXWKrLbL0DgGnUV7WHVuw9OUvL4hjgnPkIeEvESk74gAITi5G606JtZPp39cd8HA9VQzCIvA49LpPN5Q==",
-      "dev": true
-    },
     "webpod": {
       "version": "0.0.2",
       "resolved": "https://registry.npmjs.org/webpod/-/webpod-0.0.2.tgz",
@@ -11808,6 +11676,12 @@
       "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz",
       "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==",
       "dev": true
+    },
+    "zurk": {
+      "version": "0.0.27",
+      "resolved": "https://registry.npmjs.org/zurk/-/zurk-0.0.27.tgz",
+      "integrity": "sha512-BwvvxnPmiiI0H8ThWj7XSUrMN33X/JTb+qiA7/2M03jwwFtCGPwDxpNzKbI9aNKRkJu1v6XD73Y5aYY+eNyGSg==",
+      "dev": true
     }
   }
 }
package.json
@@ -55,7 +55,7 @@
   },
   "optionalDependencies": {
     "@types/fs-extra": "^11.0.4",
-    "@types/node": ">=20.11.19"
+    "@types/node": ">=20.11.28"
   },
   "devDependencies": {
     "@stryker-mutator/core": "^6.4.2",
@@ -67,9 +67,9 @@
     "c8": "^7.13.0",
     "chalk": "^5.3.0",
     "dts-bundle-generator": "^9.3.1",
-    "esbuild": "^0.20.1",
+    "esbuild": "^0.20.2",
     "esbuild-node-externals": "^1.13.0",
-    "esbuild-plugin-entry-chunks": "^0.1.8",
+    "esbuild-plugin-entry-chunks": "^0.1.11",
     "fs-extra": "^11.2.0",
     "fx": "*",
     "globby": "^14.0.1",
@@ -82,7 +82,8 @@
     "typescript": "^5.0.4",
     "webpod": "^0",
     "which": "^3.0.0",
-    "yaml": "^2.3.4"
+    "yaml": "^2.3.4",
+    "zurk": "^0.0.27"
   },
   "publishConfig": {
     "registry": "https://wombat-dressing-room.appspot.com"