diff --git a/.changeset/lucky-rules-walk.md b/.changeset/lucky-rules-walk.md
new file mode 100644
index 0000000..fa86212
--- /dev/null
+++ b/.changeset/lucky-rules-walk.md
@@ -0,0 +1,6 @@
+---
+"@e2b/desktop-python": minor
+"@e2b/desktop": minor
+---
+
+Added VNC support
diff --git a/README.md b/README.md
index cd4c4da..f1fcfeb 100644
--- a/README.md
+++ b/README.md
@@ -7,78 +7,150 @@ Each sandbox is isolated from the others and can be customized with any dependen
 ![Desktop Sandbox](readme-assets/screenshot.png)
 
 ### Example app using Computer Use with Anthropic's Claude
-Check out the [example open-source app](https://github.com/e2b-dev/secure-computer-use) in a separate repository.
 
+Check out the [example open-source app](https://github.com/e2b-dev/secure-computer-use) in a separate repository.
 
 ## 🚀 Getting started
+
 The E2B Desktop Sandbox is built on top of [E2B Sandbox](https://e2b.dev/docs).
 
 ### 1. Get E2B API key
+
 Sign up at [E2B](https://e2b.dev) and get your API key.
 Set environment variable `E2B_API_KEY` with your API key.
 
 ### 2. Install SDK
+
 **Python**
+
 ```bash
 pip install e2b-desktop
 ```
 
 **JavaScript**
+
 ```bash
 npm install @e2b/desktop
 ```
 
 ### 3. Create Desktop Sandbox
+
 **Python**
+
 ```python
 from e2b_desktop import Sandbox
 
+# Basic initialization
 desktop = Sandbox()
+
+# With custom configuration
+desktop = Sandbox(
+    display=":0",  # Custom display (defaults to :0)
+    resolution=(1920, 1080),  # Custom resolution
+    dpi=96,  # Custom DPI
+)
 ```
 
 **JavaScript**
+
 ```javascript
 import { Sandbox } from '@e2b/desktop'
 
+// Basic initialization
 const desktop = await Sandbox.create()
-```
 
-## Stream virtual desktop screen
-You can enable streaming the desktop screen by passing `videoStream: true` to the `Sandbox.create` function in JavaScript and `video_stream=True` to the `Sandbox` constructor in Python.
+// With custom configuration
+const desktop = await Sandbox.create({
+  display: ':0', // Custom display (defaults to :0)
+  resolution: [1920, 1080], // Custom resolution
+  dpi: 96, // Custom DPI
+})
+```
 
-Then call `getVideoStreamUrl` in JS and `get_video_stream_url` method in Python to get the stream URL that will look like this: `https://e2b.dev/stream/sandbox/<sandbox-id>?token=<secret-token>` and open it in your browser.
+## Features
 
-You'll need to wait a couple of seconds for the stream to buffer the first frames.
+### Streaming desktop's screen
 
 **Python**
+
 ```python
 from e2b_desktop import Sandbox
+desktop = Sandbox()
+
+# Start the stream
+desktop.stream.start()
 
-desktop = Sandbox(video_stream=True)
-stream_url = desktop.get_video_stream_url()
-print(stream_url)
-# Open stream_url in your browser
-# You'll need to wait a couple of seconds for the stream to buffer the first frames
+# Get stream URL
+url = desktop.stream.get_url()
+print(url)
+
+# Stop the stream
+desktop.stream.stop()
 ```
 
 **JavaScript**
+
 ```javascript
 import { Sandbox } from '@e2b/desktop'
 
-const desktop = await Sandbox.create({ videoStream: true, onVideoStreamStart: (streamUrl) => {
-  console.log(streamUrl)
-}})
-// Open streamUrl in your browser
-// You'll need to wait a couple of seconds for the stream to buffer the first frames
+const desktop = await Sandbox.create()
+
+// Start the stream
+await desktop.stream.start()
+
+// Get stream URL
+const url = desktop.stream.getUrl()
+console.log(url)
+
+// Stop the stream
+await desktop.stream.stop()
 ```
 
-![Desktop Sandbox](readme-assets/video-stream.png)
+### Streaming with password protection
 
-## Features
+**Python**
+
+```python
+from e2b_desktop import Sandbox
+desktop = Sandbox()
+
+# Start the stream
+desktop.stream.start(
+    enable_auth=True  # Enable authentication with an auto-generated password that will be injected in the stream URL
+)
+
+# Get stream URL
+url = desktop.stream.get_url()
+print(url)
+
+# Stop the stream
+desktop.stream.stop()
+```
+
+**JavaScript**
+
+```javascript
+import { Sandbox } from '@e2b/desktop'
+
+const desktop = await Sandbox.create()
+
+// Start the stream
+await desktop.stream.start({
+  enableAuth: true, // Enable authentication with an auto-generated password that will be injected in the stream UR
+})
+
+// Get stream URL
+const url = desktop.stream.getUrl()
+console.log(url)
+
+// Stop the stream
+await desktop.stream.stop()
+```
 
 ### Mouse control
 
 **Python**
+
 ```python
 from e2b_desktop import Sandbox
 desktop = Sandbox()
@@ -92,6 +164,7 @@ desktop.mouse_move(100, 200) # Move to x, y coordinates
 ```
 
 **JavaScript**
+
 ```javascript
 import { Sandbox } from '@e2b/desktop'
 
@@ -108,39 +181,70 @@ await desktop.moveMouse(100, 200) // Move to x, y coordinates
 ### Keyboard control
 
 **Python**
+
 ```python
 from e2b_desktop import Sandbox
 desktop = Sandbox()
 
-desktop.write("Hello, world!") # Write text at the current cursor position
-desktop.hotkey("ctrl", "c") # Press ctrl+c
+# Write text at the current cursor position with customizable typing speed
+desktop.write("Hello, world!")  # Default: chunk_size=25, delay_in_ms=75
+desktop.write("Fast typing!", chunk_size=50, delay_in_ms=25)  # Faster typing
+
+# Press keys
+desktop.press("enter")
+desktop.press("space")
+desktop.press("backspace")
+desktop.press("ctrl+c")
+```
+
+**JavaScript**
+
+```javascript
+import { Sandbox } from '@e2b/desktop'
+
+const desktop = await Sandbox.create()
+
+// Write text at the current cursor position with customizable typing speed
+await desktop.write('Hello, world!')
+await desktop.write('Fast typing!', { chunkSize: 50, delayInMs: 25 }) // Faster typing
+
+// Press keys
+await desktop.press('enter')
+await desktop.press('space')
+await desktop.press('backspace')
+await desktop.press('ctrl+c') // Copy
 ```
 
 ### Screenshot
+
+**Python**
+
 ```python
 from e2b_desktop import Sandbox
 desktop = Sandbox()
 
 # Take a screenshot and save it as "screenshot.png" locally
-image = desktop.take_screenshot()
+image = desktop.screenshot()
 # Save the image to a file
 with open("screenshot.png", "wb") as f:
     f.write(image)
 ```
 
 **JavaScript**
+
 ```javascript
 import { Sandbox } from '@e2b/desktop'
 
 const desktop = await Sandbox.create()
-const image = await desktop.takeScreenshot()
+const image = await desktop.screenshot()
 // Save the image to a file
-fs.writeFileSync("screenshot.png", image)
+fs.writeFileSync('screenshot.png', image)
 ```
 
 ### Open file
 
 **Python**
+
 ```python
 from e2b_desktop import Sandbox
 desktop = Sandbox()
@@ -151,18 +255,21 @@ desktop.open("/home/user/index.js") # Then open it
 ```
 
 **JavaScript**
+
 ```javascript
 import { Sandbox } from '@e2b/desktop'
 
 const desktop = await Sandbox.create()
 
 // Open file with default application
-await desktop.files.write("/home/user/index.js", "console.log('hello')") // First create the file
-await desktop.open("/home/user/index.js") // Then open it
+await desktop.files.write('/home/user/index.js', "console.log('hello')") // First create the file
+await desktop.open('/home/user/index.js') // Then open it
 ```
 
 ### Run any bash commands
+
 **Python**
+
 ```python
 from e2b_desktop import Sandbox
 desktop = Sandbox()
@@ -173,45 +280,18 @@ print(out)
 ```
 
 **JavaScript**
+
 ```javascript
 import { Sandbox } from '@e2b/desktop'
 
 const desktop = await Sandbox.create()
 
 // Run any bash command
-const out = await desktop.commands.run("ls -la /home/user")
+const out = await desktop.commands.run('ls -la /home/user')
 console.log(out)
 ```
 
-### Run PyAutoGUI commands
-**Python**
-```python
-from e2b_desktop import Sandbox
-desktop = Sandbox()
-
-# Run any PyAutoGUI command
-desktop.pyautogui("pyautogui.click()")
-```
-
-**JavaScript**
-```javascript
-import { Sandbox } from '@e2b/desktop'
-
-const desktop = await Sandbox.create()
-
-// Run any PyAutoGUI command
-await desktop.runPyautoguiCode("pyautogui.click()")
-```
-
-<!-- ### Customization
-```python
-from e2b_desktop import Sandbox
-desktop = Sandbox()
-``` -->
-
 ## Under the hood
-You can use [PyAutoGUI](https://pyautogui.readthedocs.io/en/latest/) to control the whole environment programmatically.
 
 The desktop-like environment is based on Linux and [Xfce](https://www.xfce.org/) at the moment. We chose Xfce because it's a fast and lightweight environment that's also popular and actively supported. However, this Sandbox template is fully customizable and you can create your own desktop environment.
 Check out the sandbox template's code [here](./template/).
-
diff --git a/package-lock.json b/package-lock.json
new file mode 100644
index 0000000..f15babe
--- /dev/null
+++ b/package-lock.json
@@ -0,0 +1,1431 @@
+{
+  "name": "e2b-desktop-root",
+  "lockfileVersion": 3,
+  "requires": true,
+  "packages": {
+    "": {
+      "name": "e2b-desktop-root",
+      "devDependencies": {
+        "@changesets/cli": "^2.26.2",
+        "@changesets/read": "^0.5.9",
+        "changeset": "^0.2.6"
+      }
+    },
+    "node_modules/@babel/runtime": {
+      "version": "7.26.7",
+      "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.26.7.tgz",
+      "integrity": "sha512-AOPI3D+a8dXnja+iwsUqGRjr1BbZIe771sXdapOtYI531gSqpi92vXivKcq2asu/DFpdl1ceFAKZyRzK2PCVcQ==",
+      "dev": true,
+      "dependencies": {
+        "regenerator-runtime": "^0.14.0"
+      },
+      "engines": {
+        "node": ">=6.9.0"
+      }
+    },
+    "node_modules/@changesets/apply-release-plan": {
+      "version": "7.0.8",
+      "resolved": "https://registry.npmjs.org/@changesets/apply-release-plan/-/apply-release-plan-7.0.8.tgz",
+      "integrity": "sha512-qjMUj4DYQ1Z6qHawsn7S71SujrExJ+nceyKKyI9iB+M5p9lCL55afuEd6uLBPRpLGWQwkwvWegDHtwHJb1UjpA==",
+      "dev": true,
+      "dependencies": {
+        "@changesets/config": "^3.0.5",
+        "@changesets/get-version-range-type": "^0.4.0",
+        "@changesets/git": "^3.0.2",
+        "@changesets/should-skip-package": "^0.1.1",
+        "@changesets/types": "^6.0.0",
+        "@manypkg/get-packages": "^1.1.3",
+        "detect-indent": "^6.0.0",
+        "fs-extra": "^7.0.1",
+        "lodash.startcase": "^4.4.0",
+        "outdent": "^0.5.0",
+        "prettier": "^2.7.1",
+        "resolve-from": "^5.0.0",
+        "semver": "^7.5.3"
+      }
+    },
+    "node_modules/@changesets/assemble-release-plan": {
+      "version": "6.0.5",
+      "resolved": "https://registry.npmjs.org/@changesets/assemble-release-plan/-/assemble-release-plan-6.0.5.tgz",
+      "integrity": "sha512-IgvBWLNKZd6k4t72MBTBK3nkygi0j3t3zdC1zrfusYo0KpdsvnDjrMM9vPnTCLCMlfNs55jRL4gIMybxa64FCQ==",
+      "dev": true,
+      "dependencies": {
+        "@changesets/errors": "^0.2.0",
+        "@changesets/get-dependents-graph": "^2.1.2",
+        "@changesets/should-skip-package": "^0.1.1",
+        "@changesets/types": "^6.0.0",
+        "@manypkg/get-packages": "^1.1.3",
+        "semver": "^7.5.3"
+      }
+    },
+    "node_modules/@changesets/changelog-git": {
+      "version": "0.2.0",
+      "resolved": "https://registry.npmjs.org/@changesets/changelog-git/-/changelog-git-0.2.0.tgz",
+      "integrity": "sha512-bHOx97iFI4OClIT35Lok3sJAwM31VbUM++gnMBV16fdbtBhgYu4dxsphBF/0AZZsyAHMrnM0yFcj5gZM1py6uQ==",
+      "dev": true,
+      "dependencies": {
+        "@changesets/types": "^6.0.0"
+      }
+    },
+    "node_modules/@changesets/cli": {
+      "version": "2.27.12",
+      "resolved": "https://registry.npmjs.org/@changesets/cli/-/cli-2.27.12.tgz",
+      "integrity": "sha512-9o3fOfHYOvBnyEn0mcahB7wzaA3P4bGJf8PNqGit5PKaMEFdsRixik+txkrJWd2VX+O6wRFXpxQL8j/1ANKE9g==",
+      "dev": true,
+      "dependencies": {
+        "@changesets/apply-release-plan": "^7.0.8",
+        "@changesets/assemble-release-plan": "^6.0.5",
+        "@changesets/changelog-git": "^0.2.0",
+        "@changesets/config": "^3.0.5",
+        "@changesets/errors": "^0.2.0",
+        "@changesets/get-dependents-graph": "^2.1.2",
+        "@changesets/get-release-plan": "^4.0.6",
+        "@changesets/git": "^3.0.2",
+        "@changesets/logger": "^0.1.1",
+        "@changesets/pre": "^2.0.1",
+        "@changesets/read": "^0.6.2",
+        "@changesets/should-skip-package": "^0.1.1",
+        "@changesets/types": "^6.0.0",
+        "@changesets/write": "^0.3.2",
+        "@manypkg/get-packages": "^1.1.3",
+        "ansi-colors": "^4.1.3",
+        "ci-info": "^3.7.0",
+        "enquirer": "^2.4.1",
+        "external-editor": "^3.1.0",
+        "fs-extra": "^7.0.1",
+        "mri": "^1.2.0",
+        "p-limit": "^2.2.0",
+        "package-manager-detector": "^0.2.0",
+        "picocolors": "^1.1.0",
+        "resolve-from": "^5.0.0",
+        "semver": "^7.5.3",
+        "spawndamnit": "^3.0.1",
+        "term-size": "^2.1.0"
+      },
+      "bin": {
+        "changeset": "bin.js"
+      }
+    },
+    "node_modules/@changesets/cli/node_modules/@changesets/parse": {
+      "version": "0.4.0",
+      "resolved": "https://registry.npmjs.org/@changesets/parse/-/parse-0.4.0.tgz",
+      "integrity": "sha512-TS/9KG2CdGXS27S+QxbZXgr8uPsP4yNJYb4BC2/NeFUj80Rni3TeD2qwWmabymxmrLo7JEsytXH1FbpKTbvivw==",
+      "dev": true,
+      "dependencies": {
+        "@changesets/types": "^6.0.0",
+        "js-yaml": "^3.13.1"
+      }
+    },
+    "node_modules/@changesets/cli/node_modules/@changesets/read": {
+      "version": "0.6.2",
+      "resolved": "https://registry.npmjs.org/@changesets/read/-/read-0.6.2.tgz",
+      "integrity": "sha512-wjfQpJvryY3zD61p8jR87mJdyx2FIhEcdXhKUqkja87toMrP/3jtg/Yg29upN+N4Ckf525/uvV7a4tzBlpk6gg==",
+      "dev": true,
+      "dependencies": {
+        "@changesets/git": "^3.0.2",
+        "@changesets/logger": "^0.1.1",
+        "@changesets/parse": "^0.4.0",
+        "@changesets/types": "^6.0.0",
+        "fs-extra": "^7.0.1",
+        "p-filter": "^2.1.0",
+        "picocolors": "^1.1.0"
+      }
+    },
+    "node_modules/@changesets/config": {
+      "version": "3.0.5",
+      "resolved": "https://registry.npmjs.org/@changesets/config/-/config-3.0.5.tgz",
+      "integrity": "sha512-QyXLSSd10GquX7hY0Mt4yQFMEeqnO5z/XLpbIr4PAkNNoQNKwDyiSrx4yd749WddusH1v3OSiA0NRAYmH/APpQ==",
+      "dev": true,
+      "dependencies": {
+        "@changesets/errors": "^0.2.0",
+        "@changesets/get-dependents-graph": "^2.1.2",
+        "@changesets/logger": "^0.1.1",
+        "@changesets/types": "^6.0.0",
+        "@manypkg/get-packages": "^1.1.3",
+        "fs-extra": "^7.0.1",
+        "micromatch": "^4.0.8"
+      }
+    },
+    "node_modules/@changesets/errors": {
+      "version": "0.2.0",
+      "resolved": "https://registry.npmjs.org/@changesets/errors/-/errors-0.2.0.tgz",
+      "integrity": "sha512-6BLOQUscTpZeGljvyQXlWOItQyU71kCdGz7Pi8H8zdw6BI0g3m43iL4xKUVPWtG+qrrL9DTjpdn8eYuCQSRpow==",
+      "dev": true,
+      "dependencies": {
+        "extendable-error": "^0.1.5"
+      }
+    },
+    "node_modules/@changesets/get-dependents-graph": {
+      "version": "2.1.2",
+      "resolved": "https://registry.npmjs.org/@changesets/get-dependents-graph/-/get-dependents-graph-2.1.2.tgz",
+      "integrity": "sha512-sgcHRkiBY9i4zWYBwlVyAjEM9sAzs4wYVwJUdnbDLnVG3QwAaia1Mk5P8M7kraTOZN+vBET7n8KyB0YXCbFRLQ==",
+      "dev": true,
+      "dependencies": {
+        "@changesets/types": "^6.0.0",
+        "@manypkg/get-packages": "^1.1.3",
+        "picocolors": "^1.1.0",
+        "semver": "^7.5.3"
+      }
+    },
+    "node_modules/@changesets/get-release-plan": {
+      "version": "4.0.6",
+      "resolved": "https://registry.npmjs.org/@changesets/get-release-plan/-/get-release-plan-4.0.6.tgz",
+      "integrity": "sha512-FHRwBkY7Eili04Y5YMOZb0ezQzKikTka4wL753vfUA5COSebt7KThqiuCN9BewE4/qFGgF/5t3AuzXx1/UAY4w==",
+      "dev": true,
+      "dependencies": {
+        "@changesets/assemble-release-plan": "^6.0.5",
+        "@changesets/config": "^3.0.5",
+        "@changesets/pre": "^2.0.1",
+        "@changesets/read": "^0.6.2",
+        "@changesets/types": "^6.0.0",
+        "@manypkg/get-packages": "^1.1.3"
+      }
+    },
+    "node_modules/@changesets/get-release-plan/node_modules/@changesets/parse": {
+      "version": "0.4.0",
+      "resolved": "https://registry.npmjs.org/@changesets/parse/-/parse-0.4.0.tgz",
+      "integrity": "sha512-TS/9KG2CdGXS27S+QxbZXgr8uPsP4yNJYb4BC2/NeFUj80Rni3TeD2qwWmabymxmrLo7JEsytXH1FbpKTbvivw==",
+      "dev": true,
+      "dependencies": {
+        "@changesets/types": "^6.0.0",
+        "js-yaml": "^3.13.1"
+      }
+    },
+    "node_modules/@changesets/get-release-plan/node_modules/@changesets/read": {
+      "version": "0.6.2",
+      "resolved": "https://registry.npmjs.org/@changesets/read/-/read-0.6.2.tgz",
+      "integrity": "sha512-wjfQpJvryY3zD61p8jR87mJdyx2FIhEcdXhKUqkja87toMrP/3jtg/Yg29upN+N4Ckf525/uvV7a4tzBlpk6gg==",
+      "dev": true,
+      "dependencies": {
+        "@changesets/git": "^3.0.2",
+        "@changesets/logger": "^0.1.1",
+        "@changesets/parse": "^0.4.0",
+        "@changesets/types": "^6.0.0",
+        "fs-extra": "^7.0.1",
+        "p-filter": "^2.1.0",
+        "picocolors": "^1.1.0"
+      }
+    },
+    "node_modules/@changesets/get-version-range-type": {
+      "version": "0.4.0",
+      "resolved": "https://registry.npmjs.org/@changesets/get-version-range-type/-/get-version-range-type-0.4.0.tgz",
+      "integrity": "sha512-hwawtob9DryoGTpixy1D3ZXbGgJu1Rhr+ySH2PvTLHvkZuQ7sRT4oQwMh0hbqZH1weAooedEjRsbrWcGLCeyVQ==",
+      "dev": true
+    },
+    "node_modules/@changesets/git": {
+      "version": "3.0.2",
+      "resolved": "https://registry.npmjs.org/@changesets/git/-/git-3.0.2.tgz",
+      "integrity": "sha512-r1/Kju9Y8OxRRdvna+nxpQIsMsRQn9dhhAZt94FLDeu0Hij2hnOozW8iqnHBgvu+KdnJppCveQwK4odwfw/aWQ==",
+      "dev": true,
+      "dependencies": {
+        "@changesets/errors": "^0.2.0",
+        "@manypkg/get-packages": "^1.1.3",
+        "is-subdir": "^1.1.1",
+        "micromatch": "^4.0.8",
+        "spawndamnit": "^3.0.1"
+      }
+    },
+    "node_modules/@changesets/logger": {
+      "version": "0.1.1",
+      "resolved": "https://registry.npmjs.org/@changesets/logger/-/logger-0.1.1.tgz",
+      "integrity": "sha512-OQtR36ZlnuTxKqoW4Sv6x5YIhOmClRd5pWsjZsddYxpWs517R0HkyiefQPIytCVh4ZcC5x9XaG8KTdd5iRQUfg==",
+      "dev": true,
+      "dependencies": {
+        "picocolors": "^1.1.0"
+      }
+    },
+    "node_modules/@changesets/parse": {
+      "version": "0.3.16",
+      "resolved": "https://registry.npmjs.org/@changesets/parse/-/parse-0.3.16.tgz",
+      "integrity": "sha512-127JKNd167ayAuBjUggZBkmDS5fIKsthnr9jr6bdnuUljroiERW7FBTDNnNVyJ4l69PzR57pk6mXQdtJyBCJKg==",
+      "dev": true,
+      "dependencies": {
+        "@changesets/types": "^5.2.1",
+        "js-yaml": "^3.13.1"
+      }
+    },
+    "node_modules/@changesets/parse/node_modules/@changesets/types": {
+      "version": "5.2.1",
+      "resolved": "https://registry.npmjs.org/@changesets/types/-/types-5.2.1.tgz",
+      "integrity": "sha512-myLfHbVOqaq9UtUKqR/nZA/OY7xFjQMdfgfqeZIBK4d0hA6pgxArvdv8M+6NUzzBsjWLOtvApv8YHr4qM+Kpfg==",
+      "dev": true
+    },
+    "node_modules/@changesets/pre": {
+      "version": "2.0.1",
+      "resolved": "https://registry.npmjs.org/@changesets/pre/-/pre-2.0.1.tgz",
+      "integrity": "sha512-vvBJ/If4jKM4tPz9JdY2kGOgWmCowUYOi5Ycv8dyLnEE8FgpYYUo1mgJZxcdtGGP3aG8rAQulGLyyXGSLkIMTQ==",
+      "dev": true,
+      "dependencies": {
+        "@changesets/errors": "^0.2.0",
+        "@changesets/types": "^6.0.0",
+        "@manypkg/get-packages": "^1.1.3",
+        "fs-extra": "^7.0.1"
+      }
+    },
+    "node_modules/@changesets/read": {
+      "version": "0.5.9",
+      "resolved": "https://registry.npmjs.org/@changesets/read/-/read-0.5.9.tgz",
+      "integrity": "sha512-T8BJ6JS6j1gfO1HFq50kU3qawYxa4NTbI/ASNVVCBTsKquy2HYwM9r7ZnzkiMe8IEObAJtUVGSrePCOxAK2haQ==",
+      "dev": true,
+      "dependencies": {
+        "@babel/runtime": "^7.20.1",
+        "@changesets/git": "^2.0.0",
+        "@changesets/logger": "^0.0.5",
+        "@changesets/parse": "^0.3.16",
+        "@changesets/types": "^5.2.1",
+        "chalk": "^2.1.0",
+        "fs-extra": "^7.0.1",
+        "p-filter": "^2.1.0"
+      }
+    },
+    "node_modules/@changesets/read/node_modules/@changesets/errors": {
+      "version": "0.1.4",
+      "resolved": "https://registry.npmjs.org/@changesets/errors/-/errors-0.1.4.tgz",
+      "integrity": "sha512-HAcqPF7snsUJ/QzkWoKfRfXushHTu+K5KZLJWPb34s4eCZShIf8BFO3fwq6KU8+G7L5KdtN2BzQAXOSXEyiY9Q==",
+      "dev": true,
+      "dependencies": {
+        "extendable-error": "^0.1.5"
+      }
+    },
+    "node_modules/@changesets/read/node_modules/@changesets/git": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/@changesets/git/-/git-2.0.0.tgz",
+      "integrity": "sha512-enUVEWbiqUTxqSnmesyJGWfzd51PY4H7mH9yUw0hPVpZBJ6tQZFMU3F3mT/t9OJ/GjyiM4770i+sehAn6ymx6A==",
+      "dev": true,
+      "dependencies": {
+        "@babel/runtime": "^7.20.1",
+        "@changesets/errors": "^0.1.4",
+        "@changesets/types": "^5.2.1",
+        "@manypkg/get-packages": "^1.1.3",
+        "is-subdir": "^1.1.1",
+        "micromatch": "^4.0.2",
+        "spawndamnit": "^2.0.0"
+      }
+    },
+    "node_modules/@changesets/read/node_modules/@changesets/logger": {
+      "version": "0.0.5",
+      "resolved": "https://registry.npmjs.org/@changesets/logger/-/logger-0.0.5.tgz",
+      "integrity": "sha512-gJyZHomu8nASHpaANzc6bkQMO9gU/ib20lqew1rVx753FOxffnCrJlGIeQVxNWCqM+o6OOleCo/ivL8UAO5iFw==",
+      "dev": true,
+      "dependencies": {
+        "chalk": "^2.1.0"
+      }
+    },
+    "node_modules/@changesets/read/node_modules/@changesets/types": {
+      "version": "5.2.1",
+      "resolved": "https://registry.npmjs.org/@changesets/types/-/types-5.2.1.tgz",
+      "integrity": "sha512-myLfHbVOqaq9UtUKqR/nZA/OY7xFjQMdfgfqeZIBK4d0hA6pgxArvdv8M+6NUzzBsjWLOtvApv8YHr4qM+Kpfg==",
+      "dev": true
+    },
+    "node_modules/@changesets/read/node_modules/cross-spawn": {
+      "version": "5.1.0",
+      "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-5.1.0.tgz",
+      "integrity": "sha512-pTgQJ5KC0d2hcY8eyL1IzlBPYjTkyH72XRZPnLyKus2mBfNjQs3klqbJU2VILqZryAZUt9JOb3h/mWMy23/f5A==",
+      "dev": true,
+      "dependencies": {
+        "lru-cache": "^4.0.1",
+        "shebang-command": "^1.2.0",
+        "which": "^1.2.9"
+      }
+    },
+    "node_modules/@changesets/read/node_modules/shebang-command": {
+      "version": "1.2.0",
+      "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-1.2.0.tgz",
+      "integrity": "sha512-EV3L1+UQWGor21OmnvojK36mhg+TyIKDh3iFBKBohr5xeXIhNBcx8oWdgkTEEQ+BEFFYdLRuqMfd5L84N1V5Vg==",
+      "dev": true,
+      "dependencies": {
+        "shebang-regex": "^1.0.0"
+      },
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/@changesets/read/node_modules/shebang-regex": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-1.0.0.tgz",
+      "integrity": "sha512-wpoSFAxys6b2a2wHZ1XpDSgD7N9iVjg29Ph9uV/uaP9Ex/KXlkTZTeddxDPSYQpgvzKLGJke2UU0AzoGCjNIvQ==",
+      "dev": true,
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/@changesets/read/node_modules/spawndamnit": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/spawndamnit/-/spawndamnit-2.0.0.tgz",
+      "integrity": "sha512-j4JKEcncSjFlqIwU5L/rp2N5SIPsdxaRsIv678+TZxZ0SRDJTm8JrxJMjE/XuiEZNEir3S8l0Fa3Ke339WI4qA==",
+      "dev": true,
+      "dependencies": {
+        "cross-spawn": "^5.1.0",
+        "signal-exit": "^3.0.2"
+      }
+    },
+    "node_modules/@changesets/read/node_modules/which": {
+      "version": "1.3.1",
+      "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz",
+      "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==",
+      "dev": true,
+      "dependencies": {
+        "isexe": "^2.0.0"
+      },
+      "bin": {
+        "which": "bin/which"
+      }
+    },
+    "node_modules/@changesets/should-skip-package": {
+      "version": "0.1.1",
+      "resolved": "https://registry.npmjs.org/@changesets/should-skip-package/-/should-skip-package-0.1.1.tgz",
+      "integrity": "sha512-H9LjLbF6mMHLtJIc/eHR9Na+MifJ3VxtgP/Y+XLn4BF7tDTEN1HNYtH6QMcjP1uxp9sjaFYmW8xqloaCi/ckTg==",
+      "dev": true,
+      "dependencies": {
+        "@changesets/types": "^6.0.0",
+        "@manypkg/get-packages": "^1.1.3"
+      }
+    },
+    "node_modules/@changesets/types": {
+      "version": "6.0.0",
+      "resolved": "https://registry.npmjs.org/@changesets/types/-/types-6.0.0.tgz",
+      "integrity": "sha512-b1UkfNulgKoWfqyHtzKS5fOZYSJO+77adgL7DLRDr+/7jhChN+QcHnbjiQVOz/U+Ts3PGNySq7diAItzDgugfQ==",
+      "dev": true
+    },
+    "node_modules/@changesets/write": {
+      "version": "0.3.2",
+      "resolved": "https://registry.npmjs.org/@changesets/write/-/write-0.3.2.tgz",
+      "integrity": "sha512-kDxDrPNpUgsjDbWBvUo27PzKX4gqeKOlhibaOXDJA6kuBisGqNHv/HwGJrAu8U/dSf8ZEFIeHIPtvSlZI1kULw==",
+      "dev": true,
+      "dependencies": {
+        "@changesets/types": "^6.0.0",
+        "fs-extra": "^7.0.1",
+        "human-id": "^1.0.2",
+        "prettier": "^2.7.1"
+      }
+    },
+    "node_modules/@manypkg/find-root": {
+      "version": "1.1.0",
+      "resolved": "https://registry.npmjs.org/@manypkg/find-root/-/find-root-1.1.0.tgz",
+      "integrity": "sha512-mki5uBvhHzO8kYYix/WRy2WX8S3B5wdVSc9D6KcU5lQNglP2yt58/VfLuAK49glRXChosY8ap2oJ1qgma3GUVA==",
+      "dev": true,
+      "dependencies": {
+        "@babel/runtime": "^7.5.5",
+        "@types/node": "^12.7.1",
+        "find-up": "^4.1.0",
+        "fs-extra": "^8.1.0"
+      }
+    },
+    "node_modules/@manypkg/find-root/node_modules/fs-extra": {
+      "version": "8.1.0",
+      "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-8.1.0.tgz",
+      "integrity": "sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g==",
+      "dev": true,
+      "dependencies": {
+        "graceful-fs": "^4.2.0",
+        "jsonfile": "^4.0.0",
+        "universalify": "^0.1.0"
+      },
+      "engines": {
+        "node": ">=6 <7 || >=8"
+      }
+    },
+    "node_modules/@manypkg/get-packages": {
+      "version": "1.1.3",
+      "resolved": "https://registry.npmjs.org/@manypkg/get-packages/-/get-packages-1.1.3.tgz",
+      "integrity": "sha512-fo+QhuU3qE/2TQMQmbVMqaQ6EWbMhi4ABWP+O4AM1NqPBuy0OrApV5LO6BrrgnhtAHS2NH6RrVk9OL181tTi8A==",
+      "dev": true,
+      "dependencies": {
+        "@babel/runtime": "^7.5.5",
+        "@changesets/types": "^4.0.1",
+        "@manypkg/find-root": "^1.1.0",
+        "fs-extra": "^8.1.0",
+        "globby": "^11.0.0",
+        "read-yaml-file": "^1.1.0"
+      }
+    },
+    "node_modules/@manypkg/get-packages/node_modules/@changesets/types": {
+      "version": "4.1.0",
+      "resolved": "https://registry.npmjs.org/@changesets/types/-/types-4.1.0.tgz",
+      "integrity": "sha512-LDQvVDv5Kb50ny2s25Fhm3d9QSZimsoUGBsUioj6MC3qbMUCuC8GPIvk/M6IvXx3lYhAs0lwWUQLb+VIEUCECw==",
+      "dev": true
+    },
+    "node_modules/@manypkg/get-packages/node_modules/fs-extra": {
+      "version": "8.1.0",
+      "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-8.1.0.tgz",
+      "integrity": "sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g==",
+      "dev": true,
+      "dependencies": {
+        "graceful-fs": "^4.2.0",
+        "jsonfile": "^4.0.0",
+        "universalify": "^0.1.0"
+      },
+      "engines": {
+        "node": ">=6 <7 || >=8"
+      }
+    },
+    "node_modules/@nodelib/fs.scandir": {
+      "version": "2.1.5",
+      "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz",
+      "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==",
+      "dev": true,
+      "dependencies": {
+        "@nodelib/fs.stat": "2.0.5",
+        "run-parallel": "^1.1.9"
+      },
+      "engines": {
+        "node": ">= 8"
+      }
+    },
+    "node_modules/@nodelib/fs.stat": {
+      "version": "2.0.5",
+      "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz",
+      "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==",
+      "dev": true,
+      "engines": {
+        "node": ">= 8"
+      }
+    },
+    "node_modules/@nodelib/fs.walk": {
+      "version": "1.2.8",
+      "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz",
+      "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==",
+      "dev": true,
+      "dependencies": {
+        "@nodelib/fs.scandir": "2.1.5",
+        "fastq": "^1.6.0"
+      },
+      "engines": {
+        "node": ">= 8"
+      }
+    },
+    "node_modules/@types/node": {
+      "version": "12.20.55",
+      "resolved": "https://registry.npmjs.org/@types/node/-/node-12.20.55.tgz",
+      "integrity": "sha512-J8xLz7q2OFulZ2cyGTLE1TbbZcjpno7FaN6zdJNrgAdrJ+DZzh/uFR6YrTb4C+nXakvud8Q4+rbhoIWlYQbUFQ==",
+      "dev": true
+    },
+    "node_modules/ansi-colors": {
+      "version": "4.1.3",
+      "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.3.tgz",
+      "integrity": "sha512-/6w/C21Pm1A7aZitlI5Ni/2J6FFQN8i1Cvz3kHABAAbw93v/NlvKdVOqz7CCWz/3iv/JplRSEEZ83XION15ovw==",
+      "dev": true,
+      "engines": {
+        "node": ">=6"
+      }
+    },
+    "node_modules/ansi-styles": {
+      "version": "3.2.1",
+      "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz",
+      "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==",
+      "dev": true,
+      "dependencies": {
+        "color-convert": "^1.9.0"
+      },
+      "engines": {
+        "node": ">=4"
+      }
+    },
+    "node_modules/argparse": {
+      "version": "1.0.10",
+      "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz",
+      "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==",
+      "dev": true,
+      "dependencies": {
+        "sprintf-js": "~1.0.2"
+      }
+    },
+    "node_modules/array-union": {
+      "version": "2.1.0",
+      "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz",
+      "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==",
+      "dev": true,
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/better-path-resolve": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/better-path-resolve/-/better-path-resolve-1.0.0.tgz",
+      "integrity": "sha512-pbnl5XzGBdrFU/wT4jqmJVPn2B6UHPBOhzMQkY/SPUPB6QtUXtmBHBIwCbXJol93mOpGMnQyP/+BB19q04xj7g==",
+      "dev": true,
+      "dependencies": {
+        "is-windows": "^1.0.0"
+      },
+      "engines": {
+        "node": ">=4"
+      }
+    },
+    "node_modules/braces": {
+      "version": "3.0.3",
+      "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz",
+      "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==",
+      "dev": true,
+      "dependencies": {
+        "fill-range": "^7.1.1"
+      },
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/chalk": {
+      "version": "2.4.2",
+      "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz",
+      "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==",
+      "dev": true,
+      "dependencies": {
+        "ansi-styles": "^3.2.1",
+        "escape-string-regexp": "^1.0.5",
+        "supports-color": "^5.3.0"
+      },
+      "engines": {
+        "node": ">=4"
+      }
+    },
+    "node_modules/changeset": {
+      "version": "0.2.6",
+      "resolved": "https://registry.npmjs.org/changeset/-/changeset-0.2.6.tgz",
+      "integrity": "sha512-d21ym9zLPOKMVhIa8ulJo5IV3QR2NNdK6BWuwg48qJA0XSQaMeDjo1UGThcTn7YDmU08j3UpKyFNvb3zplk8mw==",
+      "dev": true,
+      "dependencies": {
+        "udc": "^1.0.0",
+        "underscore": "^1.8.3"
+      }
+    },
+    "node_modules/chardet": {
+      "version": "0.7.0",
+      "resolved": "https://registry.npmjs.org/chardet/-/chardet-0.7.0.tgz",
+      "integrity": "sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA==",
+      "dev": true
+    },
+    "node_modules/ci-info": {
+      "version": "3.9.0",
+      "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-3.9.0.tgz",
+      "integrity": "sha512-NIxF55hv4nSqQswkAeiOi1r83xy8JldOFDTWiug55KBu9Jnblncd2U6ViHmYgHf01TPZS77NJBhBMKdWj9HQMQ==",
+      "dev": true,
+      "funding": [
+        {
+          "type": "github",
+          "url": "https://github.com/sponsors/sibiraj-s"
+        }
+      ],
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/color-convert": {
+      "version": "1.9.3",
+      "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz",
+      "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==",
+      "dev": true,
+      "dependencies": {
+        "color-name": "1.1.3"
+      }
+    },
+    "node_modules/color-name": {
+      "version": "1.1.3",
+      "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz",
+      "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==",
+      "dev": true
+    },
+    "node_modules/cross-spawn": {
+      "version": "7.0.6",
+      "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz",
+      "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==",
+      "dev": true,
+      "dependencies": {
+        "path-key": "^3.1.0",
+        "shebang-command": "^2.0.0",
+        "which": "^2.0.1"
+      },
+      "engines": {
+        "node": ">= 8"
+      }
+    },
+    "node_modules/detect-indent": {
+      "version": "6.1.0",
+      "resolved": "https://registry.npmjs.org/detect-indent/-/detect-indent-6.1.0.tgz",
+      "integrity": "sha512-reYkTUJAZb9gUuZ2RvVCNhVHdg62RHnJ7WJl8ftMi4diZ6NWlciOzQN88pUhSELEwflJht4oQDv0F0BMlwaYtA==",
+      "dev": true,
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/dir-glob": {
+      "version": "3.0.1",
+      "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz",
+      "integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==",
+      "dev": true,
+      "dependencies": {
+        "path-type": "^4.0.0"
+      },
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/enquirer": {
+      "version": "2.4.1",
+      "resolved": "https://registry.npmjs.org/enquirer/-/enquirer-2.4.1.tgz",
+      "integrity": "sha512-rRqJg/6gd538VHvR3PSrdRBb/1Vy2YfzHqzvbhGIQpDRKIa4FgV/54b5Q1xYSxOOwKvjXweS26E0Q+nAMwp2pQ==",
+      "dev": true,
+      "dependencies": {
+        "ansi-colors": "^4.1.1",
+        "strip-ansi": "^6.0.1"
+      },
+      "engines": {
+        "node": ">=8.6"
+      }
+    },
+    "node_modules/enquirer/node_modules/ansi-regex": {
+      "version": "5.0.1",
+      "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz",
+      "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==",
+      "dev": true,
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/enquirer/node_modules/strip-ansi": {
+      "version": "6.0.1",
+      "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz",
+      "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==",
+      "dev": true,
+      "dependencies": {
+        "ansi-regex": "^5.0.1"
+      },
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/escape-string-regexp": {
+      "version": "1.0.5",
+      "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz",
+      "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==",
+      "dev": true,
+      "engines": {
+        "node": ">=0.8.0"
+      }
+    },
+    "node_modules/esprima": {
+      "version": "4.0.1",
+      "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz",
+      "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==",
+      "dev": true,
+      "bin": {
+        "esparse": "bin/esparse.js",
+        "esvalidate": "bin/esvalidate.js"
+      },
+      "engines": {
+        "node": ">=4"
+      }
+    },
+    "node_modules/extendable-error": {
+      "version": "0.1.7",
+      "resolved": "https://registry.npmjs.org/extendable-error/-/extendable-error-0.1.7.tgz",
+      "integrity": "sha512-UOiS2in6/Q0FK0R0q6UY9vYpQ21mr/Qn1KOnte7vsACuNJf514WvCCUHSRCPcgjPT2bAhNIJdlE6bVap1GKmeg==",
+      "dev": true
+    },
+    "node_modules/external-editor": {
+      "version": "3.1.0",
+      "resolved": "https://registry.npmjs.org/external-editor/-/external-editor-3.1.0.tgz",
+      "integrity": "sha512-hMQ4CX1p1izmuLYyZqLMO/qGNw10wSv9QDCPfzXfyFrOaCSSoRfqE1Kf1s5an66J5JZC62NewG+mK49jOCtQew==",
+      "dev": true,
+      "dependencies": {
+        "chardet": "^0.7.0",
+        "iconv-lite": "^0.4.24",
+        "tmp": "^0.0.33"
+      },
+      "engines": {
+        "node": ">=4"
+      }
+    },
+    "node_modules/fast-glob": {
+      "version": "3.3.3",
+      "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.3.tgz",
+      "integrity": "sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg==",
+      "dev": true,
+      "dependencies": {
+        "@nodelib/fs.stat": "^2.0.2",
+        "@nodelib/fs.walk": "^1.2.3",
+        "glob-parent": "^5.1.2",
+        "merge2": "^1.3.0",
+        "micromatch": "^4.0.8"
+      },
+      "engines": {
+        "node": ">=8.6.0"
+      }
+    },
+    "node_modules/fastq": {
+      "version": "1.18.0",
+      "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.18.0.tgz",
+      "integrity": "sha512-QKHXPW0hD8g4UET03SdOdunzSouc9N4AuHdsX8XNcTsuz+yYFILVNIX4l9yHABMhiEI9Db0JTTIpu0wB+Y1QQw==",
+      "dev": true,
+      "dependencies": {
+        "reusify": "^1.0.4"
+      }
+    },
+    "node_modules/fill-range": {
+      "version": "7.1.1",
+      "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz",
+      "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==",
+      "dev": true,
+      "dependencies": {
+        "to-regex-range": "^5.0.1"
+      },
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/find-up": {
+      "version": "4.1.0",
+      "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz",
+      "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==",
+      "dev": true,
+      "dependencies": {
+        "locate-path": "^5.0.0",
+        "path-exists": "^4.0.0"
+      },
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/fs-extra": {
+      "version": "7.0.1",
+      "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-7.0.1.tgz",
+      "integrity": "sha512-YJDaCJZEnBmcbw13fvdAM9AwNOJwOzrE4pqMqBq5nFiEqXUqHwlK4B+3pUw6JNvfSPtX05xFHtYy/1ni01eGCw==",
+      "dev": true,
+      "dependencies": {
+        "graceful-fs": "^4.1.2",
+        "jsonfile": "^4.0.0",
+        "universalify": "^0.1.0"
+      },
+      "engines": {
+        "node": ">=6 <7 || >=8"
+      }
+    },
+    "node_modules/glob-parent": {
+      "version": "5.1.2",
+      "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz",
+      "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==",
+      "dev": true,
+      "dependencies": {
+        "is-glob": "^4.0.1"
+      },
+      "engines": {
+        "node": ">= 6"
+      }
+    },
+    "node_modules/globby": {
+      "version": "11.1.0",
+      "resolved": "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz",
+      "integrity": "sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==",
+      "dev": true,
+      "dependencies": {
+        "array-union": "^2.1.0",
+        "dir-glob": "^3.0.1",
+        "fast-glob": "^3.2.9",
+        "ignore": "^5.2.0",
+        "merge2": "^1.4.1",
+        "slash": "^3.0.0"
+      },
+      "engines": {
+        "node": ">=10"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
+    "node_modules/graceful-fs": {
+      "version": "4.2.11",
+      "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz",
+      "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==",
+      "dev": true
+    },
+    "node_modules/has-flag": {
+      "version": "3.0.0",
+      "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz",
+      "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==",
+      "dev": true,
+      "engines": {
+        "node": ">=4"
+      }
+    },
+    "node_modules/human-id": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/human-id/-/human-id-1.0.2.tgz",
+      "integrity": "sha512-UNopramDEhHJD+VR+ehk8rOslwSfByxPIZyJRfV739NDhN5LF1fa1MqnzKm2lGTQRjNrjK19Q5fhkgIfjlVUKw==",
+      "dev": true
+    },
+    "node_modules/iconv-lite": {
+      "version": "0.4.24",
+      "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz",
+      "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==",
+      "dev": true,
+      "dependencies": {
+        "safer-buffer": ">= 2.1.2 < 3"
+      },
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/ignore": {
+      "version": "5.3.2",
+      "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz",
+      "integrity": "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==",
+      "dev": true,
+      "engines": {
+        "node": ">= 4"
+      }
+    },
+    "node_modules/is-extglob": {
+      "version": "2.1.1",
+      "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz",
+      "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==",
+      "dev": true,
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/is-glob": {
+      "version": "4.0.3",
+      "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz",
+      "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==",
+      "dev": true,
+      "dependencies": {
+        "is-extglob": "^2.1.1"
+      },
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/is-number": {
+      "version": "7.0.0",
+      "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz",
+      "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==",
+      "dev": true,
+      "engines": {
+        "node": ">=0.12.0"
+      }
+    },
+    "node_modules/is-subdir": {
+      "version": "1.2.0",
+      "resolved": "https://registry.npmjs.org/is-subdir/-/is-subdir-1.2.0.tgz",
+      "integrity": "sha512-2AT6j+gXe/1ueqbW6fLZJiIw3F8iXGJtt0yDrZaBhAZEG1raiTxKWU+IPqMCzQAXOUCKdA4UDMgacKH25XG2Cw==",
+      "dev": true,
+      "dependencies": {
+        "better-path-resolve": "1.0.0"
+      },
+      "engines": {
+        "node": ">=4"
+      }
+    },
+    "node_modules/is-windows": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/is-windows/-/is-windows-1.0.2.tgz",
+      "integrity": "sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA==",
+      "dev": true,
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/isexe": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz",
+      "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==",
+      "dev": true
+    },
+    "node_modules/js-yaml": {
+      "version": "3.14.1",
+      "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz",
+      "integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==",
+      "dev": true,
+      "dependencies": {
+        "argparse": "^1.0.7",
+        "esprima": "^4.0.0"
+      },
+      "bin": {
+        "js-yaml": "bin/js-yaml.js"
+      }
+    },
+    "node_modules/jsonfile": {
+      "version": "4.0.0",
+      "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-4.0.0.tgz",
+      "integrity": "sha512-m6F1R3z8jjlf2imQHS2Qez5sjKWQzbuuhuJ/FKYFRZvPE3PuHcSMVZzfsLhGVOkfd20obL5SWEBew5ShlquNxg==",
+      "dev": true,
+      "optionalDependencies": {
+        "graceful-fs": "^4.1.6"
+      }
+    },
+    "node_modules/locate-path": {
+      "version": "5.0.0",
+      "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz",
+      "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==",
+      "dev": true,
+      "dependencies": {
+        "p-locate": "^4.1.0"
+      },
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/lodash.startcase": {
+      "version": "4.4.0",
+      "resolved": "https://registry.npmjs.org/lodash.startcase/-/lodash.startcase-4.4.0.tgz",
+      "integrity": "sha512-+WKqsK294HMSc2jEbNgpHpd0JfIBhp7rEV4aqXWqFr6AlXov+SlcgB1Fv01y2kGe3Gc8nMW7VA0SrGuSkRfIEg==",
+      "dev": true
+    },
+    "node_modules/lru-cache": {
+      "version": "4.1.5",
+      "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-4.1.5.tgz",
+      "integrity": "sha512-sWZlbEP2OsHNkXrMl5GYk/jKk70MBng6UU4YI/qGDYbgf6YbP4EvmqISbXCoJiRKs+1bSpFHVgQxvJ17F2li5g==",
+      "dev": true,
+      "dependencies": {
+        "pseudomap": "^1.0.2",
+        "yallist": "^2.1.2"
+      }
+    },
+    "node_modules/merge2": {
+      "version": "1.4.1",
+      "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz",
+      "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==",
+      "dev": true,
+      "engines": {
+        "node": ">= 8"
+      }
+    },
+    "node_modules/micromatch": {
+      "version": "4.0.8",
+      "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz",
+      "integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==",
+      "dev": true,
+      "dependencies": {
+        "braces": "^3.0.3",
+        "picomatch": "^2.3.1"
+      },
+      "engines": {
+        "node": ">=8.6"
+      }
+    },
+    "node_modules/mri": {
+      "version": "1.2.0",
+      "resolved": "https://registry.npmjs.org/mri/-/mri-1.2.0.tgz",
+      "integrity": "sha512-tzzskb3bG8LvYGFF/mDTpq3jpI6Q9wc3LEmBaghu+DdCssd1FakN7Bc0hVNmEyGq1bq3RgfkCb3cmQLpNPOroA==",
+      "dev": true,
+      "engines": {
+        "node": ">=4"
+      }
+    },
+    "node_modules/os-tmpdir": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz",
+      "integrity": "sha512-D2FR03Vir7FIu45XBY20mTb+/ZSWB00sjU9jdQXt83gDrI4Ztz5Fs7/yy74g2N5SVQY4xY1qDr4rNddwYRVX0g==",
+      "dev": true,
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/outdent": {
+      "version": "0.5.0",
+      "resolved": "https://registry.npmjs.org/outdent/-/outdent-0.5.0.tgz",
+      "integrity": "sha512-/jHxFIzoMXdqPzTaCpFzAAWhpkSjZPF4Vsn6jAfNpmbH/ymsmd7Qc6VE9BGn0L6YMj6uwpQLxCECpus4ukKS9Q==",
+      "dev": true
+    },
+    "node_modules/p-filter": {
+      "version": "2.1.0",
+      "resolved": "https://registry.npmjs.org/p-filter/-/p-filter-2.1.0.tgz",
+      "integrity": "sha512-ZBxxZ5sL2HghephhpGAQdoskxplTwr7ICaehZwLIlfL6acuVgZPm8yBNuRAFBGEqtD/hmUeq9eqLg2ys9Xr/yw==",
+      "dev": true,
+      "dependencies": {
+        "p-map": "^2.0.0"
+      },
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/p-limit": {
+      "version": "2.3.0",
+      "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz",
+      "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==",
+      "dev": true,
+      "dependencies": {
+        "p-try": "^2.0.0"
+      },
+      "engines": {
+        "node": ">=6"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
+    "node_modules/p-locate": {
+      "version": "4.1.0",
+      "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz",
+      "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==",
+      "dev": true,
+      "dependencies": {
+        "p-limit": "^2.2.0"
+      },
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/p-map": {
+      "version": "2.1.0",
+      "resolved": "https://registry.npmjs.org/p-map/-/p-map-2.1.0.tgz",
+      "integrity": "sha512-y3b8Kpd8OAN444hxfBbFfj1FY/RjtTd8tzYwhUqNYXx0fXx2iX4maP4Qr6qhIKbQXI02wTLAda4fYUbDagTUFw==",
+      "dev": true,
+      "engines": {
+        "node": ">=6"
+      }
+    },
+    "node_modules/p-try": {
+      "version": "2.2.0",
+      "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz",
+      "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==",
+      "dev": true,
+      "engines": {
+        "node": ">=6"
+      }
+    },
+    "node_modules/package-manager-detector": {
+      "version": "0.2.8",
+      "resolved": "https://registry.npmjs.org/package-manager-detector/-/package-manager-detector-0.2.8.tgz",
+      "integrity": "sha512-ts9KSdroZisdvKMWVAVCXiKqnqNfXz4+IbrBG8/BWx/TR5le+jfenvoBuIZ6UWM9nz47W7AbD9qYfAwfWMIwzA==",
+      "dev": true
+    },
+    "node_modules/path-exists": {
+      "version": "4.0.0",
+      "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz",
+      "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==",
+      "dev": true,
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/path-key": {
+      "version": "3.1.1",
+      "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz",
+      "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==",
+      "dev": true,
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/path-type": {
+      "version": "4.0.0",
+      "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz",
+      "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==",
+      "dev": true,
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/picocolors": {
+      "version": "1.1.1",
+      "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz",
+      "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==",
+      "dev": true
+    },
+    "node_modules/picomatch": {
+      "version": "2.3.1",
+      "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz",
+      "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==",
+      "dev": true,
+      "engines": {
+        "node": ">=8.6"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/jonschlinkert"
+      }
+    },
+    "node_modules/pify": {
+      "version": "4.0.1",
+      "resolved": "https://registry.npmjs.org/pify/-/pify-4.0.1.tgz",
+      "integrity": "sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==",
+      "dev": true,
+      "engines": {
+        "node": ">=6"
+      }
+    },
+    "node_modules/prettier": {
+      "version": "2.8.8",
+      "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.8.8.tgz",
+      "integrity": "sha512-tdN8qQGvNjw4CHbY+XXk0JgCXn9QiF21a55rBe5LJAU+kDyC4WQn4+awm2Xfk2lQMk5fKup9XgzTZtGkjBdP9Q==",
+      "dev": true,
+      "bin": {
+        "prettier": "bin-prettier.js"
+      },
+      "engines": {
+        "node": ">=10.13.0"
+      },
+      "funding": {
+        "url": "https://github.com/prettier/prettier?sponsor=1"
+      }
+    },
+    "node_modules/pseudomap": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/pseudomap/-/pseudomap-1.0.2.tgz",
+      "integrity": "sha512-b/YwNhb8lk1Zz2+bXXpS/LK9OisiZZ1SNsSLxN1x2OXVEhW2Ckr/7mWE5vrC1ZTiJlD9g19jWszTmJsB+oEpFQ==",
+      "dev": true
+    },
+    "node_modules/queue-microtask": {
+      "version": "1.2.3",
+      "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz",
+      "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==",
+      "dev": true,
+      "funding": [
+        {
+          "type": "github",
+          "url": "https://github.com/sponsors/feross"
+        },
+        {
+          "type": "patreon",
+          "url": "https://www.patreon.com/feross"
+        },
+        {
+          "type": "consulting",
+          "url": "https://feross.org/support"
+        }
+      ]
+    },
+    "node_modules/read-yaml-file": {
+      "version": "1.1.0",
+      "resolved": "https://registry.npmjs.org/read-yaml-file/-/read-yaml-file-1.1.0.tgz",
+      "integrity": "sha512-VIMnQi/Z4HT2Fxuwg5KrY174U1VdUIASQVWXXyqtNRtxSr9IYkn1rsI6Tb6HsrHCmB7gVpNwX6JxPTHcH6IoTA==",
+      "dev": true,
+      "dependencies": {
+        "graceful-fs": "^4.1.5",
+        "js-yaml": "^3.6.1",
+        "pify": "^4.0.1",
+        "strip-bom": "^3.0.0"
+      },
+      "engines": {
+        "node": ">=6"
+      }
+    },
+    "node_modules/regenerator-runtime": {
+      "version": "0.14.1",
+      "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.14.1.tgz",
+      "integrity": "sha512-dYnhHh0nJoMfnkZs6GmmhFknAGRrLznOu5nc9ML+EJxGvrx6H7teuevqVqCuPcPK//3eDrrjQhehXVx9cnkGdw==",
+      "dev": true
+    },
+    "node_modules/resolve-from": {
+      "version": "5.0.0",
+      "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz",
+      "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==",
+      "dev": true,
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/reusify": {
+      "version": "1.0.4",
+      "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz",
+      "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==",
+      "dev": true,
+      "engines": {
+        "iojs": ">=1.0.0",
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/run-parallel": {
+      "version": "1.2.0",
+      "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz",
+      "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==",
+      "dev": true,
+      "funding": [
+        {
+          "type": "github",
+          "url": "https://github.com/sponsors/feross"
+        },
+        {
+          "type": "patreon",
+          "url": "https://www.patreon.com/feross"
+        },
+        {
+          "type": "consulting",
+          "url": "https://feross.org/support"
+        }
+      ],
+      "dependencies": {
+        "queue-microtask": "^1.2.2"
+      }
+    },
+    "node_modules/safer-buffer": {
+      "version": "2.1.2",
+      "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz",
+      "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==",
+      "dev": true
+    },
+    "node_modules/semver": {
+      "version": "7.7.0",
+      "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.0.tgz",
+      "integrity": "sha512-DrfFnPzblFmNrIZzg5RzHegbiRWg7KMR7btwi2yjHwx06zsUbO5g613sVwEV7FTwmzJu+Io0lJe2GJ3LxqpvBQ==",
+      "dev": true,
+      "bin": {
+        "semver": "bin/semver.js"
+      },
+      "engines": {
+        "node": ">=10"
+      }
+    },
+    "node_modules/shebang-command": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz",
+      "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==",
+      "dev": true,
+      "dependencies": {
+        "shebang-regex": "^3.0.0"
+      },
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/shebang-regex": {
+      "version": "3.0.0",
+      "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz",
+      "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==",
+      "dev": true,
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/signal-exit": {
+      "version": "3.0.7",
+      "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz",
+      "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==",
+      "dev": true
+    },
+    "node_modules/slash": {
+      "version": "3.0.0",
+      "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz",
+      "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==",
+      "dev": true,
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/spawndamnit": {
+      "version": "3.0.1",
+      "resolved": "https://registry.npmjs.org/spawndamnit/-/spawndamnit-3.0.1.tgz",
+      "integrity": "sha512-MmnduQUuHCoFckZoWnXsTg7JaiLBJrKFj9UI2MbRPGaJeVpsLcVBu6P/IGZovziM/YBsellCmsprgNA+w0CzVg==",
+      "dev": true,
+      "dependencies": {
+        "cross-spawn": "^7.0.5",
+        "signal-exit": "^4.0.1"
+      }
+    },
+    "node_modules/spawndamnit/node_modules/signal-exit": {
+      "version": "4.1.0",
+      "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz",
+      "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==",
+      "dev": true,
+      "engines": {
+        "node": ">=14"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/isaacs"
+      }
+    },
+    "node_modules/sprintf-js": {
+      "version": "1.0.3",
+      "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz",
+      "integrity": "sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==",
+      "dev": true
+    },
+    "node_modules/strip-bom": {
+      "version": "3.0.0",
+      "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz",
+      "integrity": "sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==",
+      "dev": true,
+      "engines": {
+        "node": ">=4"
+      }
+    },
+    "node_modules/supports-color": {
+      "version": "5.5.0",
+      "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz",
+      "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==",
+      "dev": true,
+      "dependencies": {
+        "has-flag": "^3.0.0"
+      },
+      "engines": {
+        "node": ">=4"
+      }
+    },
+    "node_modules/term-size": {
+      "version": "2.2.1",
+      "resolved": "https://registry.npmjs.org/term-size/-/term-size-2.2.1.tgz",
+      "integrity": "sha512-wK0Ri4fOGjv/XPy8SBHZChl8CM7uMc5VML7SqiQ0zG7+J5Vr+RMQDoHa2CNT6KHUnTGIXH34UDMkPzAUyapBZg==",
+      "dev": true,
+      "engines": {
+        "node": ">=8"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
+    "node_modules/tmp": {
+      "version": "0.0.33",
+      "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.33.tgz",
+      "integrity": "sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw==",
+      "dev": true,
+      "dependencies": {
+        "os-tmpdir": "~1.0.2"
+      },
+      "engines": {
+        "node": ">=0.6.0"
+      }
+    },
+    "node_modules/to-regex-range": {
+      "version": "5.0.1",
+      "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz",
+      "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==",
+      "dev": true,
+      "dependencies": {
+        "is-number": "^7.0.0"
+      },
+      "engines": {
+        "node": ">=8.0"
+      }
+    },
+    "node_modules/udc": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/udc/-/udc-1.0.1.tgz",
+      "integrity": "sha512-jv+D9de1flsum5QkFtBdjyppCQAdz9kTck/0xST5Vx48T9LL2BYnw0Iw77dSKDQ9KZ/PS3qPO1vfXHDpLZlxcQ==",
+      "dev": true
+    },
+    "node_modules/underscore": {
+      "version": "1.13.7",
+      "resolved": "https://registry.npmjs.org/underscore/-/underscore-1.13.7.tgz",
+      "integrity": "sha512-GMXzWtsc57XAtguZgaQViUOzs0KTkk8ojr3/xAxXLITqf/3EMwxC0inyETfDFjH/Krbhuep0HNbbjI9i/q3F3g==",
+      "dev": true
+    },
+    "node_modules/universalify": {
+      "version": "0.1.2",
+      "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz",
+      "integrity": "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==",
+      "dev": true,
+      "engines": {
+        "node": ">= 4.0.0"
+      }
+    },
+    "node_modules/which": {
+      "version": "2.0.2",
+      "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz",
+      "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==",
+      "dev": true,
+      "dependencies": {
+        "isexe": "^2.0.0"
+      },
+      "bin": {
+        "node-which": "bin/node-which"
+      },
+      "engines": {
+        "node": ">= 8"
+      }
+    },
+    "node_modules/yallist": {
+      "version": "2.1.2",
+      "resolved": "https://registry.npmjs.org/yallist/-/yallist-2.1.2.tgz",
+      "integrity": "sha512-ncTzHV7NvsQZkYe1DW7cbDLm0YpzHmZF5r/iyP3ZnQtMiJ+pjzisCiMNI+Sj+xQF5pXhSHxSB3uDbsBTzY/c2A==",
+      "dev": true
+    }
+  }
+}
\ No newline at end of file
diff --git a/packages/js-sdk/README.md b/packages/js-sdk/README.md
new file mode 100644
index 0000000..7b3a63f
--- /dev/null
+++ b/packages/js-sdk/README.md
@@ -0,0 +1,155 @@
+# E2B Desktop Sandbox - Virtual Computer for Computer Use
+
+E2B Desktop Sandbox is a secure virtual desktop ready for Computer Use. Powered by [E2B](https://e2b.dev).
+
+Each sandbox is isolated from the others and can be customized with any dependencies you want.
+
+![Desktop Sandbox](../../readme-assets/screenshot.png)
+
+### Example app using Computer Use with Anthropic's Claude
+
+Check out the [example open-source app](https://github.com/e2b-dev/secure-computer-use) in a separate repository.
+
+## 🚀 Getting started
+
+The E2B Desktop Sandbox is built on top of [E2B Sandbox](https://e2b.dev/docs).
+
+### 1. Get E2B API key
+
+Sign up at [E2B](https://e2b.dev) and get your API key.
+Set environment variable `E2B_API_KEY` with your API key.
+
+### 2. Install SDK
+
+```bash
+npm install @e2b/desktop
+```
+
+### 3. Create Desktop Sandbox
+
+```javascript
+import { Sandbox } from '@e2b/desktop'
+
+// Basic initialization
+const desktop = await Sandbox.create()
+
+// With custom configuration
+const desktop = await Sandbox.create({
+  display: ':0', // Custom display (defaults to :0)
+  resolution: [1920, 1080], // Custom resolution
+  dpi: 96 // Custom DPI
+})
+```
+
+## Features
+
+### Streaming desktop's screen
+
+```javascript
+import { Sandbox } from '@e2b/desktop'
+
+const desktop = await Sandbox.create()
+
+// Start the stream
+await desktop.stream.start()
+
+// Get stream URL
+const url = desktop.stream.getUrl()
+console.log(url)
+
+// Stop the stream
+await desktop.stream.stop()
+```
+
+### Streaming with password protection
+
+```javascript
+import { Sandbox } from '@e2b/desktop'
+
+const desktop = await Sandbox.create()
+
+// Start the stream
+await desktop.stream.start({
+  enableAuth: true, // Enable authentication with an auto-generated password that will be injected in the stream UR
+})
+
+// Get stream URL
+const url = desktop.stream.getUrl()
+console.log(url)
+
+// Stop the stream
+await desktop.stream.stop()
+```
+
+### Mouse control
+
+```javascript
+import { Sandbox } from '@e2b/desktop'
+
+const desktop = await Sandbox.create()
+
+await desktop.doubleClick()
+await desktop.leftClick()
+await desktop.rightClick()
+await desktop.middleClick()
+await desktop.scroll(10) // Scroll by the amount. Positive for up, negative for down.
+await desktop.moveMouse(100, 200) // Move to x, y coordinates
+```
+
+### Keyboard control
+
+```javascript
+import { Sandbox } from '@e2b/desktop'
+
+const desktop = await Sandbox.create()
+
+// Write text at the current cursor position with customizable typing speed
+await desktop.write('Hello, world!')
+await desktop.write('Fast typing!', { chunkSize: 50, delayInMs: 25 }) // Faster typing
+
+// Press keys
+await desktop.press('enter')
+await desktop.press('space')
+await desktop.press('backspace')
+await desktop.press('ctrl+c') // Copy
+```
+
+### Screenshot
+
+```javascript
+import { Sandbox } from '@e2b/desktop'
+
+const desktop = await Sandbox.create()
+const image = await desktop.screenshot()
+// Save the image to a file
+fs.writeFileSync('screenshot.png', image)
+```
+
+### Open file
+
+```javascript
+import { Sandbox } from '@e2b/desktop'
+
+const desktop = await Sandbox.create()
+
+// Open file with default application
+await desktop.files.write('/home/user/index.js', "console.log('hello')") // First create the file
+await desktop.open('/home/user/index.js') // Then open it
+```
+
+### Run any bash commands
+
+```javascript
+import { Sandbox } from '@e2b/desktop'
+
+const desktop = await Sandbox.create()
+
+// Run any bash command
+const out = await desktop.commands.run('ls -la /home/user')
+console.log(out)
+```
+
+## Under the hood
+
+The desktop-like environment is based on Linux and [Xfce](https://www.xfce.org/) at the moment. We chose Xfce because it's a fast and lightweight environment that's also popular and actively supported. However, this Sandbox template is fully customizable and you can create your own desktop environment.
+Check out the sandbox template's code [here](./template/).
diff --git a/packages/js-sdk/example.mts b/packages/js-sdk/example.mts
index 7a3b6db..be2ce3d 100644
--- a/packages/js-sdk/example.mts
+++ b/packages/js-sdk/example.mts
@@ -2,50 +2,46 @@ import { config } from 'dotenv'
 
 config()
 import { Sandbox } from './dist'
+import { writeFileSync } from 'fs';
 
 
-const sbx = await Sandbox.create({
-  videoStream: true,
-  onVideoStreamStart: (url) => console.log('Video stream started:', url)
-})
+console.log("Starting desktop sandbox...")
 
-// const command = "ffmpeg -video_size 1024x768 -f x11grab -i :99 -c:v libx264 -c:a aac  -g 50 -b:v 4000k -maxrate 4000k -bufsize 8000k -f flv rtmp://global-live.mux.com:5222/app/stream-key"
-// const ffmpeg = await sbx.commands.run(command, { background: true, onStdout: (data) => console.log(data.toString()) })
+console.time('--> Sandbox creation time');
+const desktop = await Sandbox.create();
+console.timeEnd('--> Sandbox creation time');
 
-for (let i = 0; i < 30; i++) {
-  const x = Math.floor(Math.random() * 1024);
-  const y = Math.floor(Math.random() * 768);
-  await sbx.moveMouse(x, y);
-  await new Promise(resolve => setTimeout(resolve, 2000));
-  await sbx.rightClick();
-  console.log('right clicked', i)
-}
+console.log("Desktop Sandbox started, ID:", desktop.sandboxId)
+console.log("Screen size:", await desktop.getScreenSize())
+
+await desktop.stream.start({
+  enableAuth: true
+})
+
+console.log("Stream URL:", desktop.stream.getUrl())
 
+await new Promise(resolve => setTimeout(resolve, 5000));
 
-// await sbx.kill()
+console.log("Moving mouse to 'Applications' and clicking...")
+await desktop.moveMouse(100, 100)
+await desktop.leftClick()
+console.log("Cursor position:", await desktop.getCursorPosition())
 
+await new Promise(resolve => setTimeout(resolve, 1000));
 
-// // await sbx.rightClick()
-// let imageData = await sbx.takeScreenshot()
-// await processImage(imageData)
-// // const pos = await sbx.locateTextOnScreen('Applications')
-// // if (!pos) throw new Error('Text not found on screen')
-// await sbx.moveMouse(384 + 150, 1024 - 80)
-// // await new Promise(resolve => setTimeout(resolve, 5000));
-// await sbx.doubleClick()
-// // await sbx.leftClick()
-// console.log('clicked')
-// await new Promise(resolve => setTimeout(resolve, 2000));
-// console.log('screenshot')
-// imageData = await sbx.takeScreenshot()
-// await processImage(imageData)
-// await sbx.kill()
+const screenshot = await desktop.screenshot("bytes")
+writeFileSync('1.png', Buffer.from(screenshot));
 
 
+for (let i = 0; i < 20; i++) {
+  const x = Math.floor(Math.random() * 1024);
+  const y = Math.floor(Math.random() * 768);
+  await desktop.moveMouse(x, y);
+  await new Promise(resolve => setTimeout(resolve, 2000));
+  await desktop.rightClick();
+  console.log('right clicked', i)
+}
 
 
-// {
-//   text: 'File System',
-//   confidence: 95.43375396728516,
-//   bbox: { x0: 33, y0: 228, x1: 107, y1: 241 }
-// }
+await desktop.stream.stop()
+await desktop.kill()
diff --git a/packages/js-sdk/package-lock.json b/packages/js-sdk/package-lock.json
new file mode 100644
index 0000000..297ff14
--- /dev/null
+++ b/packages/js-sdk/package-lock.json
@@ -0,0 +1,2950 @@
+{
+  "name": "@e2b/desktop",
+  "version": "1.0.3",
+  "lockfileVersion": 3,
+  "requires": true,
+  "packages": {
+    "": {
+      "name": "@e2b/desktop",
+      "version": "1.0.3",
+      "dependencies": {
+        "e2b": "^1.0.7"
+      },
+      "devDependencies": {
+        "@types/node": "^22.13.9",
+        "dotenv": "^16.4.5",
+        "tsup": "^8.3.5",
+        "tsx": "^4.19.2",
+        "typedoc": "^0.27.9",
+        "typedoc-plugin-markdown": "^4.2.7",
+        "typescript": "^5.6.3",
+        "vitest": "^3.0.5"
+      },
+      "engines": {
+        "node": ">=18"
+      }
+    },
+    "node_modules/@bufbuild/protobuf": {
+      "version": "2.2.3",
+      "resolved": "https://registry.npmjs.org/@bufbuild/protobuf/-/protobuf-2.2.3.tgz",
+      "integrity": "sha512-tFQoXHJdkEOSwj5tRIZSPNUuXK3RaR7T1nUrPgbYX1pUbvqqaaZAsfo+NXBPsz5rZMSKVFrgK1WL8Q/MSLvprg=="
+    },
+    "node_modules/@connectrpc/connect": {
+      "version": "2.0.0-rc.3",
+      "resolved": "https://registry.npmjs.org/@connectrpc/connect/-/connect-2.0.0-rc.3.tgz",
+      "integrity": "sha512-ARBt64yEyKbanyRETTjcjJuHr2YXorzQo0etyS5+P6oSeW8xEuzajA9g+zDnMcj1hlX2dQE93foIWQGfpru7gQ==",
+      "peerDependencies": {
+        "@bufbuild/protobuf": "^2.2.0"
+      }
+    },
+    "node_modules/@connectrpc/connect-web": {
+      "version": "2.0.0-rc.3",
+      "resolved": "https://registry.npmjs.org/@connectrpc/connect-web/-/connect-web-2.0.0-rc.3.tgz",
+      "integrity": "sha512-w88P8Lsn5CCsA7MFRl2e6oLY4J/5toiNtJns/YJrlyQaWOy3RO8pDgkz+iIkG98RPMhj2thuBvsd3Cn4DKKCkw==",
+      "peerDependencies": {
+        "@bufbuild/protobuf": "^2.2.0",
+        "@connectrpc/connect": "2.0.0-rc.3"
+      }
+    },
+    "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==",
+      "cpu": [
+        "ppc64"
+      ],
+      "dev": true,
+      "optional": true,
+      "os": [
+        "aix"
+      ],
+      "engines": {
+        "node": ">=18"
+      }
+    },
+    "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==",
+      "cpu": [
+        "arm"
+      ],
+      "dev": true,
+      "optional": true,
+      "os": [
+        "android"
+      ],
+      "engines": {
+        "node": ">=18"
+      }
+    },
+    "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==",
+      "cpu": [
+        "arm64"
+      ],
+      "dev": true,
+      "optional": true,
+      "os": [
+        "android"
+      ],
+      "engines": {
+        "node": ">=18"
+      }
+    },
+    "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==",
+      "cpu": [
+        "x64"
+      ],
+      "dev": true,
+      "optional": true,
+      "os": [
+        "android"
+      ],
+      "engines": {
+        "node": ">=18"
+      }
+    },
+    "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==",
+      "cpu": [
+        "arm64"
+      ],
+      "dev": true,
+      "optional": true,
+      "os": [
+        "darwin"
+      ],
+      "engines": {
+        "node": ">=18"
+      }
+    },
+    "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==",
+      "cpu": [
+        "x64"
+      ],
+      "dev": true,
+      "optional": true,
+      "os": [
+        "darwin"
+      ],
+      "engines": {
+        "node": ">=18"
+      }
+    },
+    "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==",
+      "cpu": [
+        "arm64"
+      ],
+      "dev": true,
+      "optional": true,
+      "os": [
+        "freebsd"
+      ],
+      "engines": {
+        "node": ">=18"
+      }
+    },
+    "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==",
+      "cpu": [
+        "x64"
+      ],
+      "dev": true,
+      "optional": true,
+      "os": [
+        "freebsd"
+      ],
+      "engines": {
+        "node": ">=18"
+      }
+    },
+    "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==",
+      "cpu": [
+        "arm"
+      ],
+      "dev": true,
+      "optional": true,
+      "os": [
+        "linux"
+      ],
+      "engines": {
+        "node": ">=18"
+      }
+    },
+    "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==",
+      "cpu": [
+        "arm64"
+      ],
+      "dev": true,
+      "optional": true,
+      "os": [
+        "linux"
+      ],
+      "engines": {
+        "node": ">=18"
+      }
+    },
+    "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==",
+      "cpu": [
+        "ia32"
+      ],
+      "dev": true,
+      "optional": true,
+      "os": [
+        "linux"
+      ],
+      "engines": {
+        "node": ">=18"
+      }
+    },
+    "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==",
+      "cpu": [
+        "loong64"
+      ],
+      "dev": true,
+      "optional": true,
+      "os": [
+        "linux"
+      ],
+      "engines": {
+        "node": ">=18"
+      }
+    },
+    "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==",
+      "cpu": [
+        "mips64el"
+      ],
+      "dev": true,
+      "optional": true,
+      "os": [
+        "linux"
+      ],
+      "engines": {
+        "node": ">=18"
+      }
+    },
+    "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==",
+      "cpu": [
+        "ppc64"
+      ],
+      "dev": true,
+      "optional": true,
+      "os": [
+        "linux"
+      ],
+      "engines": {
+        "node": ">=18"
+      }
+    },
+    "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==",
+      "cpu": [
+        "riscv64"
+      ],
+      "dev": true,
+      "optional": true,
+      "os": [
+        "linux"
+      ],
+      "engines": {
+        "node": ">=18"
+      }
+    },
+    "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==",
+      "cpu": [
+        "s390x"
+      ],
+      "dev": true,
+      "optional": true,
+      "os": [
+        "linux"
+      ],
+      "engines": {
+        "node": ">=18"
+      }
+    },
+    "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==",
+      "cpu": [
+        "x64"
+      ],
+      "dev": true,
+      "optional": true,
+      "os": [
+        "linux"
+      ],
+      "engines": {
+        "node": ">=18"
+      }
+    },
+    "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==",
+      "cpu": [
+        "arm64"
+      ],
+      "dev": true,
+      "optional": true,
+      "os": [
+        "netbsd"
+      ],
+      "engines": {
+        "node": ">=18"
+      }
+    },
+    "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==",
+      "cpu": [
+        "x64"
+      ],
+      "dev": true,
+      "optional": true,
+      "os": [
+        "netbsd"
+      ],
+      "engines": {
+        "node": ">=18"
+      }
+    },
+    "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==",
+      "cpu": [
+        "arm64"
+      ],
+      "dev": true,
+      "optional": true,
+      "os": [
+        "openbsd"
+      ],
+      "engines": {
+        "node": ">=18"
+      }
+    },
+    "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==",
+      "cpu": [
+        "x64"
+      ],
+      "dev": true,
+      "optional": true,
+      "os": [
+        "openbsd"
+      ],
+      "engines": {
+        "node": ">=18"
+      }
+    },
+    "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==",
+      "cpu": [
+        "x64"
+      ],
+      "dev": true,
+      "optional": true,
+      "os": [
+        "sunos"
+      ],
+      "engines": {
+        "node": ">=18"
+      }
+    },
+    "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==",
+      "cpu": [
+        "arm64"
+      ],
+      "dev": true,
+      "optional": true,
+      "os": [
+        "win32"
+      ],
+      "engines": {
+        "node": ">=18"
+      }
+    },
+    "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==",
+      "cpu": [
+        "ia32"
+      ],
+      "dev": true,
+      "optional": true,
+      "os": [
+        "win32"
+      ],
+      "engines": {
+        "node": ">=18"
+      }
+    },
+    "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==",
+      "cpu": [
+        "x64"
+      ],
+      "dev": true,
+      "optional": true,
+      "os": [
+        "win32"
+      ],
+      "engines": {
+        "node": ">=18"
+      }
+    },
+    "node_modules/@gerrit0/mini-shiki": {
+      "version": "1.27.2",
+      "resolved": "https://registry.npmjs.org/@gerrit0/mini-shiki/-/mini-shiki-1.27.2.tgz",
+      "integrity": "sha512-GeWyHz8ao2gBiUW4OJnQDxXQnFgZQwwQk05t/CVVgNBN7/rK8XZ7xY6YhLVv9tH3VppWWmr9DCl3MwemB/i+Og==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "@shikijs/engine-oniguruma": "^1.27.2",
+        "@shikijs/types": "^1.27.2",
+        "@shikijs/vscode-textmate": "^10.0.1"
+      }
+    },
+    "node_modules/@isaacs/cliui": {
+      "version": "8.0.2",
+      "resolved": "https://registry.npmjs.org/@isaacs/cliui/-/cliui-8.0.2.tgz",
+      "integrity": "sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==",
+      "dev": true,
+      "dependencies": {
+        "string-width": "^5.1.2",
+        "string-width-cjs": "npm:string-width@^4.2.0",
+        "strip-ansi": "^7.0.1",
+        "strip-ansi-cjs": "npm:strip-ansi@^6.0.1",
+        "wrap-ansi": "^8.1.0",
+        "wrap-ansi-cjs": "npm:wrap-ansi@^7.0.0"
+      },
+      "engines": {
+        "node": ">=12"
+      }
+    },
+    "node_modules/@jridgewell/gen-mapping": {
+      "version": "0.3.8",
+      "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.8.tgz",
+      "integrity": "sha512-imAbBGkb+ebQyxKgzv5Hu2nmROxoDOXHh80evxdoXNOrvAnVx7zimzc1Oo5h9RlfV4vPXaE2iM5pOFbvOCClWA==",
+      "dev": true,
+      "dependencies": {
+        "@jridgewell/set-array": "^1.2.1",
+        "@jridgewell/sourcemap-codec": "^1.4.10",
+        "@jridgewell/trace-mapping": "^0.3.24"
+      },
+      "engines": {
+        "node": ">=6.0.0"
+      }
+    },
+    "node_modules/@jridgewell/resolve-uri": {
+      "version": "3.1.2",
+      "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz",
+      "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==",
+      "dev": true,
+      "engines": {
+        "node": ">=6.0.0"
+      }
+    },
+    "node_modules/@jridgewell/set-array": {
+      "version": "1.2.1",
+      "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.2.1.tgz",
+      "integrity": "sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A==",
+      "dev": true,
+      "engines": {
+        "node": ">=6.0.0"
+      }
+    },
+    "node_modules/@jridgewell/sourcemap-codec": {
+      "version": "1.5.0",
+      "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.0.tgz",
+      "integrity": "sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ==",
+      "dev": true
+    },
+    "node_modules/@jridgewell/trace-mapping": {
+      "version": "0.3.25",
+      "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.25.tgz",
+      "integrity": "sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==",
+      "dev": true,
+      "dependencies": {
+        "@jridgewell/resolve-uri": "^3.1.0",
+        "@jridgewell/sourcemap-codec": "^1.4.14"
+      }
+    },
+    "node_modules/@pkgjs/parseargs": {
+      "version": "0.11.0",
+      "resolved": "https://registry.npmjs.org/@pkgjs/parseargs/-/parseargs-0.11.0.tgz",
+      "integrity": "sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==",
+      "dev": true,
+      "optional": true,
+      "engines": {
+        "node": ">=14"
+      }
+    },
+    "node_modules/@rollup/rollup-android-arm-eabi": {
+      "version": "4.34.2",
+      "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.34.2.tgz",
+      "integrity": "sha512-6Fyg9yQbwJR+ykVdT9sid1oc2ewejS6h4wzQltmJfSW53N60G/ah9pngXGANdy9/aaE/TcUFpWosdm7JXS1WTQ==",
+      "cpu": [
+        "arm"
+      ],
+      "dev": true,
+      "optional": true,
+      "os": [
+        "android"
+      ]
+    },
+    "node_modules/@rollup/rollup-android-arm64": {
+      "version": "4.34.2",
+      "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.34.2.tgz",
+      "integrity": "sha512-K5GfWe+vtQ3kyEbihrimM38UgX57UqHp+oME7X/EX9Im6suwZfa7Hsr8AtzbJvukTpwMGs+4s29YMSO3rwWtsw==",
+      "cpu": [
+        "arm64"
+      ],
+      "dev": true,
+      "optional": true,
+      "os": [
+        "android"
+      ]
+    },
+    "node_modules/@rollup/rollup-darwin-arm64": {
+      "version": "4.34.2",
+      "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.34.2.tgz",
+      "integrity": "sha512-PSN58XG/V/tzqDb9kDGutUruycgylMlUE59f40ny6QIRNsTEIZsrNQTJKUN2keMMSmlzgunMFqyaGLmly39sug==",
+      "cpu": [
+        "arm64"
+      ],
+      "dev": true,
+      "optional": true,
+      "os": [
+        "darwin"
+      ]
+    },
+    "node_modules/@rollup/rollup-darwin-x64": {
+      "version": "4.34.2",
+      "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.34.2.tgz",
+      "integrity": "sha512-gQhK788rQJm9pzmXyfBB84VHViDERhAhzGafw+E5mUpnGKuxZGkMVDa3wgDFKT6ukLC5V7QTifzsUKdNVxp5qQ==",
+      "cpu": [
+        "x64"
+      ],
+      "dev": true,
+      "optional": true,
+      "os": [
+        "darwin"
+      ]
+    },
+    "node_modules/@rollup/rollup-freebsd-arm64": {
+      "version": "4.34.2",
+      "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.34.2.tgz",
+      "integrity": "sha512-eiaHgQwGPpxLC3+zTAcdKl4VsBl3r0AiJOd1Um/ArEzAjN/dbPK1nROHrVkdnoE6p7Svvn04w3f/jEZSTVHunA==",
+      "cpu": [
+        "arm64"
+      ],
+      "dev": true,
+      "optional": true,
+      "os": [
+        "freebsd"
+      ]
+    },
+    "node_modules/@rollup/rollup-freebsd-x64": {
+      "version": "4.34.2",
+      "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.34.2.tgz",
+      "integrity": "sha512-lhdiwQ+jf8pewYOTG4bag0Qd68Jn1v2gO1i0mTuiD+Qkt5vNfHVK/jrT7uVvycV8ZchlzXp5HDVmhpzjC6mh0g==",
+      "cpu": [
+        "x64"
+      ],
+      "dev": true,
+      "optional": true,
+      "os": [
+        "freebsd"
+      ]
+    },
+    "node_modules/@rollup/rollup-linux-arm-gnueabihf": {
+      "version": "4.34.2",
+      "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.34.2.tgz",
+      "integrity": "sha512-lfqTpWjSvbgQP1vqGTXdv+/kxIznKXZlI109WkIFPbud41bjigjNmOAAKoazmRGx+k9e3rtIdbq2pQZPV1pMig==",
+      "cpu": [
+        "arm"
+      ],
+      "dev": true,
+      "optional": true,
+      "os": [
+        "linux"
+      ]
+    },
+    "node_modules/@rollup/rollup-linux-arm-musleabihf": {
+      "version": "4.34.2",
+      "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.34.2.tgz",
+      "integrity": "sha512-RGjqULqIurqqv+NJTyuPgdZhka8ImMLB32YwUle2BPTDqDoXNgwFjdjQC59FbSk08z0IqlRJjrJ0AvDQ5W5lpw==",
+      "cpu": [
+        "arm"
+      ],
+      "dev": true,
+      "optional": true,
+      "os": [
+        "linux"
+      ]
+    },
+    "node_modules/@rollup/rollup-linux-arm64-gnu": {
+      "version": "4.34.2",
+      "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.34.2.tgz",
+      "integrity": "sha512-ZvkPiheyXtXlFqHpsdgscx+tZ7hoR59vOettvArinEspq5fxSDSgfF+L5wqqJ9R4t+n53nyn0sKxeXlik7AY9Q==",
+      "cpu": [
+        "arm64"
+      ],
+      "dev": true,
+      "optional": true,
+      "os": [
+        "linux"
+      ]
+    },
+    "node_modules/@rollup/rollup-linux-arm64-musl": {
+      "version": "4.34.2",
+      "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.34.2.tgz",
+      "integrity": "sha512-UlFk+E46TZEoxD9ufLKDBzfSG7Ki03fo6hsNRRRHF+KuvNZ5vd1RRVQm8YZlGsjcJG8R252XFK0xNPay+4WV7w==",
+      "cpu": [
+        "arm64"
+      ],
+      "dev": true,
+      "optional": true,
+      "os": [
+        "linux"
+      ]
+    },
+    "node_modules/@rollup/rollup-linux-loongarch64-gnu": {
+      "version": "4.34.2",
+      "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loongarch64-gnu/-/rollup-linux-loongarch64-gnu-4.34.2.tgz",
+      "integrity": "sha512-hJhfsD9ykx59jZuuoQgYT1GEcNNi3RCoEmbo5OGfG8RlHOiVS7iVNev9rhLKh7UBYq409f4uEw0cclTXx8nh8Q==",
+      "cpu": [
+        "loong64"
+      ],
+      "dev": true,
+      "optional": true,
+      "os": [
+        "linux"
+      ]
+    },
+    "node_modules/@rollup/rollup-linux-powerpc64le-gnu": {
+      "version": "4.34.2",
+      "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-powerpc64le-gnu/-/rollup-linux-powerpc64le-gnu-4.34.2.tgz",
+      "integrity": "sha512-g/O5IpgtrQqPegvqopvmdCF9vneLE7eqYfdPWW8yjPS8f63DNam3U4ARL1PNNB64XHZDHKpvO2Giftf43puB8Q==",
+      "cpu": [
+        "ppc64"
+      ],
+      "dev": true,
+      "optional": true,
+      "os": [
+        "linux"
+      ]
+    },
+    "node_modules/@rollup/rollup-linux-riscv64-gnu": {
+      "version": "4.34.2",
+      "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.34.2.tgz",
+      "integrity": "sha512-bSQijDC96M6PuooOuXHpvXUYiIwsnDmqGU8+br2U7iPoykNi9JtMUpN7K6xml29e0evK0/g0D1qbAUzWZFHY5Q==",
+      "cpu": [
+        "riscv64"
+      ],
+      "dev": true,
+      "optional": true,
+      "os": [
+        "linux"
+      ]
+    },
+    "node_modules/@rollup/rollup-linux-s390x-gnu": {
+      "version": "4.34.2",
+      "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.34.2.tgz",
+      "integrity": "sha512-49TtdeVAsdRuiUHXPrFVucaP4SivazetGUVH8CIxVsNsaPHV4PFkpLmH9LeqU/R4Nbgky9lzX5Xe1NrzLyraVA==",
+      "cpu": [
+        "s390x"
+      ],
+      "dev": true,
+      "optional": true,
+      "os": [
+        "linux"
+      ]
+    },
+    "node_modules/@rollup/rollup-linux-x64-gnu": {
+      "version": "4.34.2",
+      "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.34.2.tgz",
+      "integrity": "sha512-j+jFdfOycLIQ7FWKka9Zd3qvsIyugg5LeZuHF6kFlXo6MSOc6R1w37YUVy8VpAKd81LMWGi5g9J25P09M0SSIw==",
+      "cpu": [
+        "x64"
+      ],
+      "dev": true,
+      "optional": true,
+      "os": [
+        "linux"
+      ]
+    },
+    "node_modules/@rollup/rollup-linux-x64-musl": {
+      "version": "4.34.2",
+      "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.34.2.tgz",
+      "integrity": "sha512-aDPHyM/D2SpXfSNCVWCxyHmOqN9qb7SWkY1+vaXqMNMXslZYnwh9V/UCudl6psyG0v6Ukj7pXanIpfZwCOEMUg==",
+      "cpu": [
+        "x64"
+      ],
+      "dev": true,
+      "optional": true,
+      "os": [
+        "linux"
+      ]
+    },
+    "node_modules/@rollup/rollup-win32-arm64-msvc": {
+      "version": "4.34.2",
+      "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.34.2.tgz",
+      "integrity": "sha512-LQRkCyUBnAo7r8dbEdtNU08EKLCJMgAk2oP5H3R7BnUlKLqgR3dUjrLBVirmc1RK6U6qhtDw29Dimeer8d5hzQ==",
+      "cpu": [
+        "arm64"
+      ],
+      "dev": true,
+      "optional": true,
+      "os": [
+        "win32"
+      ]
+    },
+    "node_modules/@rollup/rollup-win32-ia32-msvc": {
+      "version": "4.34.2",
+      "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.34.2.tgz",
+      "integrity": "sha512-wt8OhpQUi6JuPFkm1wbVi1BByeag87LDFzeKSXzIdGcX4bMLqORTtKxLoCbV57BHYNSUSOKlSL4BYYUghainYA==",
+      "cpu": [
+        "ia32"
+      ],
+      "dev": true,
+      "optional": true,
+      "os": [
+        "win32"
+      ]
+    },
+    "node_modules/@rollup/rollup-win32-x64-msvc": {
+      "version": "4.34.2",
+      "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.34.2.tgz",
+      "integrity": "sha512-rUrqINax0TvrPBXrFKg0YbQx18NpPN3NNrgmaao9xRNbTwek7lOXObhx8tQy8gelmQ/gLaGy1WptpU2eKJZImg==",
+      "cpu": [
+        "x64"
+      ],
+      "dev": true,
+      "optional": true,
+      "os": [
+        "win32"
+      ]
+    },
+    "node_modules/@shikijs/engine-oniguruma": {
+      "version": "1.29.2",
+      "resolved": "https://registry.npmjs.org/@shikijs/engine-oniguruma/-/engine-oniguruma-1.29.2.tgz",
+      "integrity": "sha512-7iiOx3SG8+g1MnlzZVDYiaeHe7Ez2Kf2HrJzdmGwkRisT7r4rak0e655AcM/tF9JG/kg5fMNYlLLKglbN7gBqA==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "@shikijs/types": "1.29.2",
+        "@shikijs/vscode-textmate": "^10.0.1"
+      }
+    },
+    "node_modules/@shikijs/types": {
+      "version": "1.29.2",
+      "resolved": "https://registry.npmjs.org/@shikijs/types/-/types-1.29.2.tgz",
+      "integrity": "sha512-VJjK0eIijTZf0QSTODEXCqinjBn0joAHQ+aPSBzrv4O2d/QSbsMw+ZeSRx03kV34Hy7NzUvV/7NqfYGRLrASmw==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "@shikijs/vscode-textmate": "^10.0.1",
+        "@types/hast": "^3.0.4"
+      }
+    },
+    "node_modules/@shikijs/vscode-textmate": {
+      "version": "10.0.2",
+      "resolved": "https://registry.npmjs.org/@shikijs/vscode-textmate/-/vscode-textmate-10.0.2.tgz",
+      "integrity": "sha512-83yeghZ2xxin3Nj8z1NMd/NCuca+gsYXswywDy5bHvwlWL8tpTQmzGeUuHd9FC3E/SBEMvzJRwWEOz5gGes9Qg==",
+      "dev": true,
+      "license": "MIT"
+    },
+    "node_modules/@types/estree": {
+      "version": "1.0.6",
+      "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.6.tgz",
+      "integrity": "sha512-AYnb1nQyY49te+VRAVgmzfcgjYS91mY5P0TKUDCLEM+gNnA+3T6rWITXRLYCpahpqSQbN5cE+gHpnPyXjHWxcw==",
+      "dev": true
+    },
+    "node_modules/@types/hast": {
+      "version": "3.0.4",
+      "resolved": "https://registry.npmjs.org/@types/hast/-/hast-3.0.4.tgz",
+      "integrity": "sha512-WPs+bbQw5aCj+x6laNGWLH3wviHtoCv/P3+otBhbOhJgG8qtpdAMlTCxLtsTWA7LH1Oh/bFCHsBn0TPS5m30EQ==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "@types/unist": "*"
+      }
+    },
+    "node_modules/@types/node": {
+      "version": "22.13.9",
+      "resolved": "https://registry.npmjs.org/@types/node/-/node-22.13.9.tgz",
+      "integrity": "sha512-acBjXdRJ3A6Pb3tqnw9HZmyR3Fiol3aGxRCK1x3d+6CDAMjl7I649wpSd+yNURCjbOUGu9tqtLKnTGxmK6CyGw==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "undici-types": "~6.20.0"
+      }
+    },
+    "node_modules/@types/unist": {
+      "version": "3.0.3",
+      "resolved": "https://registry.npmjs.org/@types/unist/-/unist-3.0.3.tgz",
+      "integrity": "sha512-ko/gIFJRv177XgZsZcBwnqJN5x/Gien8qNOn0D5bQU/zAzVf9Zt3BlcUiLqhV9y4ARk0GbT3tnUiPNgnTXzc/Q==",
+      "dev": true,
+      "license": "MIT"
+    },
+    "node_modules/@vitest/expect": {
+      "version": "3.0.5",
+      "resolved": "https://registry.npmjs.org/@vitest/expect/-/expect-3.0.5.tgz",
+      "integrity": "sha512-nNIOqupgZ4v5jWuQx2DSlHLEs7Q4Oh/7AYwNyE+k0UQzG7tSmjPXShUikn1mpNGzYEN2jJbTvLejwShMitovBA==",
+      "dev": true,
+      "dependencies": {
+        "@vitest/spy": "3.0.5",
+        "@vitest/utils": "3.0.5",
+        "chai": "^5.1.2",
+        "tinyrainbow": "^2.0.0"
+      },
+      "funding": {
+        "url": "https://opencollective.com/vitest"
+      }
+    },
+    "node_modules/@vitest/mocker": {
+      "version": "3.0.5",
+      "resolved": "https://registry.npmjs.org/@vitest/mocker/-/mocker-3.0.5.tgz",
+      "integrity": "sha512-CLPNBFBIE7x6aEGbIjaQAX03ZZlBMaWwAjBdMkIf/cAn6xzLTiM3zYqO/WAbieEjsAZir6tO71mzeHZoodThvw==",
+      "dev": true,
+      "dependencies": {
+        "@vitest/spy": "3.0.5",
+        "estree-walker": "^3.0.3",
+        "magic-string": "^0.30.17"
+      },
+      "funding": {
+        "url": "https://opencollective.com/vitest"
+      },
+      "peerDependencies": {
+        "msw": "^2.4.9",
+        "vite": "^5.0.0 || ^6.0.0"
+      },
+      "peerDependenciesMeta": {
+        "msw": {
+          "optional": true
+        },
+        "vite": {
+          "optional": true
+        }
+      }
+    },
+    "node_modules/@vitest/pretty-format": {
+      "version": "3.0.5",
+      "resolved": "https://registry.npmjs.org/@vitest/pretty-format/-/pretty-format-3.0.5.tgz",
+      "integrity": "sha512-CjUtdmpOcm4RVtB+up8r2vVDLR16Mgm/bYdkGFe3Yj/scRfCpbSi2W/BDSDcFK7ohw8UXvjMbOp9H4fByd/cOA==",
+      "dev": true,
+      "dependencies": {
+        "tinyrainbow": "^2.0.0"
+      },
+      "funding": {
+        "url": "https://opencollective.com/vitest"
+      }
+    },
+    "node_modules/@vitest/runner": {
+      "version": "3.0.5",
+      "resolved": "https://registry.npmjs.org/@vitest/runner/-/runner-3.0.5.tgz",
+      "integrity": "sha512-BAiZFityFexZQi2yN4OX3OkJC6scwRo8EhRB0Z5HIGGgd2q+Nq29LgHU/+ovCtd0fOfXj5ZI6pwdlUmC5bpi8A==",
+      "dev": true,
+      "dependencies": {
+        "@vitest/utils": "3.0.5",
+        "pathe": "^2.0.2"
+      },
+      "funding": {
+        "url": "https://opencollective.com/vitest"
+      }
+    },
+    "node_modules/@vitest/snapshot": {
+      "version": "3.0.5",
+      "resolved": "https://registry.npmjs.org/@vitest/snapshot/-/snapshot-3.0.5.tgz",
+      "integrity": "sha512-GJPZYcd7v8QNUJ7vRvLDmRwl+a1fGg4T/54lZXe+UOGy47F9yUfE18hRCtXL5aHN/AONu29NGzIXSVFh9K0feA==",
+      "dev": true,
+      "dependencies": {
+        "@vitest/pretty-format": "3.0.5",
+        "magic-string": "^0.30.17",
+        "pathe": "^2.0.2"
+      },
+      "funding": {
+        "url": "https://opencollective.com/vitest"
+      }
+    },
+    "node_modules/@vitest/spy": {
+      "version": "3.0.5",
+      "resolved": "https://registry.npmjs.org/@vitest/spy/-/spy-3.0.5.tgz",
+      "integrity": "sha512-5fOzHj0WbUNqPK6blI/8VzZdkBlQLnT25knX0r4dbZI9qoZDf3qAdjoMmDcLG5A83W6oUUFJgUd0EYBc2P5xqg==",
+      "dev": true,
+      "dependencies": {
+        "tinyspy": "^3.0.2"
+      },
+      "funding": {
+        "url": "https://opencollective.com/vitest"
+      }
+    },
+    "node_modules/@vitest/utils": {
+      "version": "3.0.5",
+      "resolved": "https://registry.npmjs.org/@vitest/utils/-/utils-3.0.5.tgz",
+      "integrity": "sha512-N9AX0NUoUtVwKwy21JtwzaqR5L5R5A99GAbrHfCCXK1lp593i/3AZAXhSP43wRQuxYsflrdzEfXZFo1reR1Nkg==",
+      "dev": true,
+      "dependencies": {
+        "@vitest/pretty-format": "3.0.5",
+        "loupe": "^3.1.2",
+        "tinyrainbow": "^2.0.0"
+      },
+      "funding": {
+        "url": "https://opencollective.com/vitest"
+      }
+    },
+    "node_modules/ansi-regex": {
+      "version": "6.1.0",
+      "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.1.0.tgz",
+      "integrity": "sha512-7HSX4QQb4CspciLpVFwyRe79O3xsIZDDLER21kERQ71oaPodF8jL725AgJMFAYbooIqolJoRLuM81SpeUkpkvA==",
+      "dev": true,
+      "engines": {
+        "node": ">=12"
+      },
+      "funding": {
+        "url": "https://github.com/chalk/ansi-regex?sponsor=1"
+      }
+    },
+    "node_modules/ansi-styles": {
+      "version": "6.2.1",
+      "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.1.tgz",
+      "integrity": "sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==",
+      "dev": true,
+      "engines": {
+        "node": ">=12"
+      },
+      "funding": {
+        "url": "https://github.com/chalk/ansi-styles?sponsor=1"
+      }
+    },
+    "node_modules/any-promise": {
+      "version": "1.3.0",
+      "resolved": "https://registry.npmjs.org/any-promise/-/any-promise-1.3.0.tgz",
+      "integrity": "sha512-7UvmKalWRt1wgjL1RrGxoSJW/0QZFIegpeGvZG9kjp8vrRu55XTHbwnqq2GpXm9uLbcuhxm3IqX9OB4MZR1b2A==",
+      "dev": true
+    },
+    "node_modules/argparse": {
+      "version": "2.0.1",
+      "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz",
+      "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==",
+      "dev": true
+    },
+    "node_modules/assertion-error": {
+      "version": "2.0.1",
+      "resolved": "https://registry.npmjs.org/assertion-error/-/assertion-error-2.0.1.tgz",
+      "integrity": "sha512-Izi8RQcffqCeNVgFigKli1ssklIbpHnCYc6AknXGYoB6grJqyeby7jv12JUQgmTAnIDnbck1uxksT4dzN3PWBA==",
+      "dev": true,
+      "engines": {
+        "node": ">=12"
+      }
+    },
+    "node_modules/balanced-match": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz",
+      "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==",
+      "dev": true
+    },
+    "node_modules/brace-expansion": {
+      "version": "2.0.1",
+      "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz",
+      "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==",
+      "dev": true,
+      "dependencies": {
+        "balanced-match": "^1.0.0"
+      }
+    },
+    "node_modules/bundle-require": {
+      "version": "5.1.0",
+      "resolved": "https://registry.npmjs.org/bundle-require/-/bundle-require-5.1.0.tgz",
+      "integrity": "sha512-3WrrOuZiyaaZPWiEt4G3+IffISVC9HYlWueJEBWED4ZH4aIAC2PnkdnuRrR94M+w6yGWn4AglWtJtBI8YqvgoA==",
+      "dev": true,
+      "dependencies": {
+        "load-tsconfig": "^0.2.3"
+      },
+      "engines": {
+        "node": "^12.20.0 || ^14.13.1 || >=16.0.0"
+      },
+      "peerDependencies": {
+        "esbuild": ">=0.18"
+      }
+    },
+    "node_modules/cac": {
+      "version": "6.7.14",
+      "resolved": "https://registry.npmjs.org/cac/-/cac-6.7.14.tgz",
+      "integrity": "sha512-b6Ilus+c3RrdDk+JhLKUAQfzzgLEPy6wcXqS7f/xe1EETvsDP6GORG7SFuOs6cID5YkqchW/LXZbX5bc8j7ZcQ==",
+      "dev": true,
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/chai": {
+      "version": "5.1.2",
+      "resolved": "https://registry.npmjs.org/chai/-/chai-5.1.2.tgz",
+      "integrity": "sha512-aGtmf24DW6MLHHG5gCx4zaI3uBq3KRtxeVs0DjFH6Z0rDNbsvTxFASFvdj79pxjxZ8/5u3PIiN3IwEIQkiiuPw==",
+      "dev": true,
+      "dependencies": {
+        "assertion-error": "^2.0.1",
+        "check-error": "^2.1.1",
+        "deep-eql": "^5.0.1",
+        "loupe": "^3.1.0",
+        "pathval": "^2.0.0"
+      },
+      "engines": {
+        "node": ">=12"
+      }
+    },
+    "node_modules/check-error": {
+      "version": "2.1.1",
+      "resolved": "https://registry.npmjs.org/check-error/-/check-error-2.1.1.tgz",
+      "integrity": "sha512-OAlb+T7V4Op9OwdkjmguYRqncdlx5JiofwOAUkmTF+jNdHwzTaTs4sRAGpzLF3oOz5xAyDGrPgeIDFQmDOTiJw==",
+      "dev": true,
+      "engines": {
+        "node": ">= 16"
+      }
+    },
+    "node_modules/chokidar": {
+      "version": "4.0.3",
+      "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-4.0.3.tgz",
+      "integrity": "sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA==",
+      "dev": true,
+      "dependencies": {
+        "readdirp": "^4.0.1"
+      },
+      "engines": {
+        "node": ">= 14.16.0"
+      },
+      "funding": {
+        "url": "https://paulmillr.com/funding/"
+      }
+    },
+    "node_modules/color-convert": {
+      "version": "2.0.1",
+      "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
+      "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
+      "dev": true,
+      "dependencies": {
+        "color-name": "~1.1.4"
+      },
+      "engines": {
+        "node": ">=7.0.0"
+      }
+    },
+    "node_modules/color-name": {
+      "version": "1.1.4",
+      "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
+      "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
+      "dev": true
+    },
+    "node_modules/commander": {
+      "version": "4.1.1",
+      "resolved": "https://registry.npmjs.org/commander/-/commander-4.1.1.tgz",
+      "integrity": "sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA==",
+      "dev": true,
+      "engines": {
+        "node": ">= 6"
+      }
+    },
+    "node_modules/compare-versions": {
+      "version": "6.1.1",
+      "resolved": "https://registry.npmjs.org/compare-versions/-/compare-versions-6.1.1.tgz",
+      "integrity": "sha512-4hm4VPpIecmlg59CHXnRDnqGplJFrbLG4aFEl5vl6cK1u76ws3LLvX7ikFnTDl5vo39sjWD6AaDPYodJp/NNHg=="
+    },
+    "node_modules/consola": {
+      "version": "3.4.0",
+      "resolved": "https://registry.npmjs.org/consola/-/consola-3.4.0.tgz",
+      "integrity": "sha512-EiPU8G6dQG0GFHNR8ljnZFki/8a+cQwEQ+7wpxdChl02Q8HXlwEZWD5lqAF8vC2sEC3Tehr8hy7vErz88LHyUA==",
+      "dev": true,
+      "engines": {
+        "node": "^14.18.0 || >=16.10.0"
+      }
+    },
+    "node_modules/cross-spawn": {
+      "version": "7.0.6",
+      "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz",
+      "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==",
+      "dev": true,
+      "dependencies": {
+        "path-key": "^3.1.0",
+        "shebang-command": "^2.0.0",
+        "which": "^2.0.1"
+      },
+      "engines": {
+        "node": ">= 8"
+      }
+    },
+    "node_modules/debug": {
+      "version": "4.4.0",
+      "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.0.tgz",
+      "integrity": "sha512-6WTZ/IxCY/T6BALoZHaE4ctp9xm+Z5kY/pzYaCHRFeyVhojxlrm+46y68HA6hr0TcwEssoxNiDEUJQjfPZ/RYA==",
+      "dev": true,
+      "dependencies": {
+        "ms": "^2.1.3"
+      },
+      "engines": {
+        "node": ">=6.0"
+      },
+      "peerDependenciesMeta": {
+        "supports-color": {
+          "optional": true
+        }
+      }
+    },
+    "node_modules/deep-eql": {
+      "version": "5.0.2",
+      "resolved": "https://registry.npmjs.org/deep-eql/-/deep-eql-5.0.2.tgz",
+      "integrity": "sha512-h5k/5U50IJJFpzfL6nO9jaaumfjO/f2NjK/oYB2Djzm4p9L+3T9qWpZqZ2hAbLPuuYq9wrU08WQyBTL5GbPk5Q==",
+      "dev": true,
+      "engines": {
+        "node": ">=6"
+      }
+    },
+    "node_modules/dotenv": {
+      "version": "16.4.7",
+      "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.4.7.tgz",
+      "integrity": "sha512-47qPchRCykZC03FhkYAhrvwU4xDBFIj1QPqaarj6mdM/hgUzfPHcpkHJOn3mJAufFeeAxAzeGsr5X0M4k6fLZQ==",
+      "dev": true,
+      "engines": {
+        "node": ">=12"
+      },
+      "funding": {
+        "url": "https://dotenvx.com"
+      }
+    },
+    "node_modules/e2b": {
+      "version": "1.0.7",
+      "resolved": "https://registry.npmjs.org/e2b/-/e2b-1.0.7.tgz",
+      "integrity": "sha512-7msagBbQ8tm51qaGp+hdaaaMjGG3zCzZtUS8bnz+LK7wdwtVTA1PmX+1Br9E3R7v6XIchnNWRpei+VjvGcfidA==",
+      "dependencies": {
+        "@bufbuild/protobuf": "^2.2.2",
+        "@connectrpc/connect": "2.0.0-rc.3",
+        "@connectrpc/connect-web": "2.0.0-rc.3",
+        "compare-versions": "^6.1.0",
+        "openapi-fetch": "^0.9.7",
+        "platform": "^1.3.6"
+      },
+      "engines": {
+        "node": ">=18"
+      }
+    },
+    "node_modules/eastasianwidth": {
+      "version": "0.2.0",
+      "resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz",
+      "integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==",
+      "dev": true
+    },
+    "node_modules/emoji-regex": {
+      "version": "9.2.2",
+      "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz",
+      "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==",
+      "dev": true
+    },
+    "node_modules/entities": {
+      "version": "4.5.0",
+      "resolved": "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz",
+      "integrity": "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==",
+      "dev": true,
+      "engines": {
+        "node": ">=0.12"
+      },
+      "funding": {
+        "url": "https://github.com/fb55/entities?sponsor=1"
+      }
+    },
+    "node_modules/es-module-lexer": {
+      "version": "1.6.0",
+      "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-1.6.0.tgz",
+      "integrity": "sha512-qqnD1yMU6tk/jnaMosogGySTZP8YtUgAffA9nMN+E/rjxcfRQ6IEk7IiozUjgxKoFHBGjTLnrHB/YC45r/59EQ==",
+      "dev": true
+    },
+    "node_modules/esbuild": {
+      "version": "0.24.2",
+      "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.24.2.tgz",
+      "integrity": "sha512-+9egpBW8I3CD5XPe0n6BfT5fxLzxrlDzqydF3aviG+9ni1lDC/OvMHcxqEFV0+LANZG5R1bFMWfUrjVsdwxJvA==",
+      "dev": true,
+      "hasInstallScript": true,
+      "bin": {
+        "esbuild": "bin/esbuild"
+      },
+      "engines": {
+        "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"
+      }
+    },
+    "node_modules/estree-walker": {
+      "version": "3.0.3",
+      "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-3.0.3.tgz",
+      "integrity": "sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g==",
+      "dev": true,
+      "dependencies": {
+        "@types/estree": "^1.0.0"
+      }
+    },
+    "node_modules/expect-type": {
+      "version": "1.1.0",
+      "resolved": "https://registry.npmjs.org/expect-type/-/expect-type-1.1.0.tgz",
+      "integrity": "sha512-bFi65yM+xZgk+u/KRIpekdSYkTB5W1pEf0Lt8Q8Msh7b+eQ7LXVtIB1Bkm4fvclDEL1b2CZkMhv2mOeF8tMdkA==",
+      "dev": true,
+      "engines": {
+        "node": ">=12.0.0"
+      }
+    },
+    "node_modules/fdir": {
+      "version": "6.4.3",
+      "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.4.3.tgz",
+      "integrity": "sha512-PMXmW2y1hDDfTSRc9gaXIuCCRpuoz3Kaz8cUelp3smouvfT632ozg2vrT6lJsHKKOF59YLbOGfAWGUcKEfRMQw==",
+      "dev": true,
+      "peerDependencies": {
+        "picomatch": "^3 || ^4"
+      },
+      "peerDependenciesMeta": {
+        "picomatch": {
+          "optional": true
+        }
+      }
+    },
+    "node_modules/foreground-child": {
+      "version": "3.3.0",
+      "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.3.0.tgz",
+      "integrity": "sha512-Ld2g8rrAyMYFXBhEqMz8ZAHBi4J4uS1i/CxGMDnjyFWddMXLVcDp051DZfu+t7+ab7Wv6SMqpWmyFIj5UbfFvg==",
+      "dev": true,
+      "dependencies": {
+        "cross-spawn": "^7.0.0",
+        "signal-exit": "^4.0.1"
+      },
+      "engines": {
+        "node": ">=14"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/isaacs"
+      }
+    },
+    "node_modules/fsevents": {
+      "version": "2.3.3",
+      "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz",
+      "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==",
+      "dev": true,
+      "hasInstallScript": true,
+      "optional": true,
+      "os": [
+        "darwin"
+      ],
+      "engines": {
+        "node": "^8.16.0 || ^10.6.0 || >=11.0.0"
+      }
+    },
+    "node_modules/get-tsconfig": {
+      "version": "4.10.0",
+      "resolved": "https://registry.npmjs.org/get-tsconfig/-/get-tsconfig-4.10.0.tgz",
+      "integrity": "sha512-kGzZ3LWWQcGIAmg6iWvXn0ei6WDtV26wzHRMwDSzmAbcXrTEXxHy6IehI6/4eT6VRKyMP1eF1VqwrVUmE/LR7A==",
+      "dev": true,
+      "dependencies": {
+        "resolve-pkg-maps": "^1.0.0"
+      },
+      "funding": {
+        "url": "https://github.com/privatenumber/get-tsconfig?sponsor=1"
+      }
+    },
+    "node_modules/glob": {
+      "version": "10.4.5",
+      "resolved": "https://registry.npmjs.org/glob/-/glob-10.4.5.tgz",
+      "integrity": "sha512-7Bv8RF0k6xjo7d4A/PxYLbUCfb6c+Vpd2/mB2yRDlew7Jb5hEXiCD9ibfO7wpk8i4sevK6DFny9h7EYbM3/sHg==",
+      "dev": true,
+      "dependencies": {
+        "foreground-child": "^3.1.0",
+        "jackspeak": "^3.1.2",
+        "minimatch": "^9.0.4",
+        "minipass": "^7.1.2",
+        "package-json-from-dist": "^1.0.0",
+        "path-scurry": "^1.11.1"
+      },
+      "bin": {
+        "glob": "dist/esm/bin.mjs"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/isaacs"
+      }
+    },
+    "node_modules/is-fullwidth-code-point": {
+      "version": "3.0.0",
+      "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz",
+      "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==",
+      "dev": true,
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/isexe": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz",
+      "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==",
+      "dev": true
+    },
+    "node_modules/jackspeak": {
+      "version": "3.4.3",
+      "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-3.4.3.tgz",
+      "integrity": "sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw==",
+      "dev": true,
+      "dependencies": {
+        "@isaacs/cliui": "^8.0.2"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/isaacs"
+      },
+      "optionalDependencies": {
+        "@pkgjs/parseargs": "^0.11.0"
+      }
+    },
+    "node_modules/joycon": {
+      "version": "3.1.1",
+      "resolved": "https://registry.npmjs.org/joycon/-/joycon-3.1.1.tgz",
+      "integrity": "sha512-34wB/Y7MW7bzjKRjUKTa46I2Z7eV62Rkhva+KkopW7Qvv/OSWBqvkSY7vusOPrNuZcUG3tApvdVgNB8POj3SPw==",
+      "dev": true,
+      "engines": {
+        "node": ">=10"
+      }
+    },
+    "node_modules/lilconfig": {
+      "version": "3.1.3",
+      "resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-3.1.3.tgz",
+      "integrity": "sha512-/vlFKAoH5Cgt3Ie+JLhRbwOsCQePABiU3tJ1egGvyQ+33R/vcwM2Zl2QR/LzjsBeItPt3oSVXapn+m4nQDvpzw==",
+      "dev": true,
+      "engines": {
+        "node": ">=14"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/antonk52"
+      }
+    },
+    "node_modules/lines-and-columns": {
+      "version": "1.2.4",
+      "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz",
+      "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==",
+      "dev": true
+    },
+    "node_modules/linkify-it": {
+      "version": "5.0.0",
+      "resolved": "https://registry.npmjs.org/linkify-it/-/linkify-it-5.0.0.tgz",
+      "integrity": "sha512-5aHCbzQRADcdP+ATqnDuhhJ/MRIqDkZX5pyjFHRRysS8vZ5AbqGEoFIb6pYHPZ+L/OC2Lc+xT8uHVVR5CAK/wQ==",
+      "dev": true,
+      "dependencies": {
+        "uc.micro": "^2.0.0"
+      }
+    },
+    "node_modules/load-tsconfig": {
+      "version": "0.2.5",
+      "resolved": "https://registry.npmjs.org/load-tsconfig/-/load-tsconfig-0.2.5.tgz",
+      "integrity": "sha512-IXO6OCs9yg8tMKzfPZ1YmheJbZCiEsnBdcB03l0OcfK9prKnJb96siuHCr5Fl37/yo9DnKU+TLpxzTUspw9shg==",
+      "dev": true,
+      "engines": {
+        "node": "^12.20.0 || ^14.13.1 || >=16.0.0"
+      }
+    },
+    "node_modules/lodash.sortby": {
+      "version": "4.7.0",
+      "resolved": "https://registry.npmjs.org/lodash.sortby/-/lodash.sortby-4.7.0.tgz",
+      "integrity": "sha512-HDWXG8isMntAyRF5vZ7xKuEvOhT4AhlRt/3czTSjvGUxjYCBVRQY48ViDHyfYz9VIoBkW4TMGQNapx+l3RUwdA==",
+      "dev": true
+    },
+    "node_modules/loupe": {
+      "version": "3.1.3",
+      "resolved": "https://registry.npmjs.org/loupe/-/loupe-3.1.3.tgz",
+      "integrity": "sha512-kkIp7XSkP78ZxJEsSxW3712C6teJVoeHHwgo9zJ380de7IYyJ2ISlxojcH2pC5OFLewESmnRi/+XCDIEEVyoug==",
+      "dev": true
+    },
+    "node_modules/lru-cache": {
+      "version": "10.4.3",
+      "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.4.3.tgz",
+      "integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==",
+      "dev": true
+    },
+    "node_modules/lunr": {
+      "version": "2.3.9",
+      "resolved": "https://registry.npmjs.org/lunr/-/lunr-2.3.9.tgz",
+      "integrity": "sha512-zTU3DaZaF3Rt9rhN3uBMGQD3dD2/vFQqnvZCDv4dl5iOzq2IZQqTxu90r4E5J+nP70J3ilqVCrbho2eWaeW8Ow==",
+      "dev": true
+    },
+    "node_modules/magic-string": {
+      "version": "0.30.17",
+      "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.17.tgz",
+      "integrity": "sha512-sNPKHvyjVf7gyjwS4xGTaW/mCnF8wnjtifKBEhxfZ7E/S8tQ0rssrwGNn6q8JH/ohItJfSQp9mBtQYuTlH5QnA==",
+      "dev": true,
+      "dependencies": {
+        "@jridgewell/sourcemap-codec": "^1.5.0"
+      }
+    },
+    "node_modules/markdown-it": {
+      "version": "14.1.0",
+      "resolved": "https://registry.npmjs.org/markdown-it/-/markdown-it-14.1.0.tgz",
+      "integrity": "sha512-a54IwgWPaeBCAAsv13YgmALOF1elABB08FxO9i+r4VFk5Vl4pKokRPeX8u5TCgSsPi6ec1otfLjdOpVcgbpshg==",
+      "dev": true,
+      "dependencies": {
+        "argparse": "^2.0.1",
+        "entities": "^4.4.0",
+        "linkify-it": "^5.0.0",
+        "mdurl": "^2.0.0",
+        "punycode.js": "^2.3.1",
+        "uc.micro": "^2.1.0"
+      },
+      "bin": {
+        "markdown-it": "bin/markdown-it.mjs"
+      }
+    },
+    "node_modules/mdurl": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/mdurl/-/mdurl-2.0.0.tgz",
+      "integrity": "sha512-Lf+9+2r+Tdp5wXDXC4PcIBjTDtq4UKjCPMQhKIuzpJNW0b96kVqSwW0bT7FhRSfmAiFYgP+SCRvdrDozfh0U5w==",
+      "dev": true
+    },
+    "node_modules/minimatch": {
+      "version": "9.0.5",
+      "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz",
+      "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==",
+      "dev": true,
+      "dependencies": {
+        "brace-expansion": "^2.0.1"
+      },
+      "engines": {
+        "node": ">=16 || 14 >=14.17"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/isaacs"
+      }
+    },
+    "node_modules/minipass": {
+      "version": "7.1.2",
+      "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.2.tgz",
+      "integrity": "sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==",
+      "dev": true,
+      "engines": {
+        "node": ">=16 || 14 >=14.17"
+      }
+    },
+    "node_modules/ms": {
+      "version": "2.1.3",
+      "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
+      "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==",
+      "dev": true
+    },
+    "node_modules/mz": {
+      "version": "2.7.0",
+      "resolved": "https://registry.npmjs.org/mz/-/mz-2.7.0.tgz",
+      "integrity": "sha512-z81GNO7nnYMEhrGh9LeymoE4+Yr0Wn5McHIZMK5cfQCl+NDX08sCZgUc9/6MHni9IWuFLm1Z3HTCXu2z9fN62Q==",
+      "dev": true,
+      "dependencies": {
+        "any-promise": "^1.0.0",
+        "object-assign": "^4.0.1",
+        "thenify-all": "^1.0.0"
+      }
+    },
+    "node_modules/nanoid": {
+      "version": "3.3.8",
+      "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.8.tgz",
+      "integrity": "sha512-WNLf5Sd8oZxOm+TzppcYk8gVOgP+l58xNy58D0nbUnOxOWRWvlcCV4kUF7ltmI6PsrLl/BgKEyS4mqsGChFN0w==",
+      "dev": true,
+      "funding": [
+        {
+          "type": "github",
+          "url": "https://github.com/sponsors/ai"
+        }
+      ],
+      "bin": {
+        "nanoid": "bin/nanoid.cjs"
+      },
+      "engines": {
+        "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1"
+      }
+    },
+    "node_modules/object-assign": {
+      "version": "4.1.1",
+      "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz",
+      "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==",
+      "dev": true,
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/openapi-fetch": {
+      "version": "0.9.8",
+      "resolved": "https://registry.npmjs.org/openapi-fetch/-/openapi-fetch-0.9.8.tgz",
+      "integrity": "sha512-zM6elH0EZStD/gSiNlcPrzXcVQ/pZo3BDvC6CDwRDUt1dDzxlshpmQnpD6cZaJ39THaSmwVCxxRrPKNM1hHrDg==",
+      "dependencies": {
+        "openapi-typescript-helpers": "^0.0.8"
+      }
+    },
+    "node_modules/openapi-typescript-helpers": {
+      "version": "0.0.8",
+      "resolved": "https://registry.npmjs.org/openapi-typescript-helpers/-/openapi-typescript-helpers-0.0.8.tgz",
+      "integrity": "sha512-1eNjQtbfNi5Z/kFhagDIaIRj6qqDzhjNJKz8cmMW0CVdGwT6e1GLbAfgI0d28VTJa1A8jz82jm/4dG8qNoNS8g=="
+    },
+    "node_modules/package-json-from-dist": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/package-json-from-dist/-/package-json-from-dist-1.0.1.tgz",
+      "integrity": "sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw==",
+      "dev": true
+    },
+    "node_modules/path-key": {
+      "version": "3.1.1",
+      "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz",
+      "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==",
+      "dev": true,
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/path-scurry": {
+      "version": "1.11.1",
+      "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-1.11.1.tgz",
+      "integrity": "sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA==",
+      "dev": true,
+      "dependencies": {
+        "lru-cache": "^10.2.0",
+        "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0"
+      },
+      "engines": {
+        "node": ">=16 || 14 >=14.18"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/isaacs"
+      }
+    },
+    "node_modules/pathe": {
+      "version": "2.0.2",
+      "resolved": "https://registry.npmjs.org/pathe/-/pathe-2.0.2.tgz",
+      "integrity": "sha512-15Ztpk+nov8DR524R4BF7uEuzESgzUEAV4Ah7CUMNGXdE5ELuvxElxGXndBl32vMSsWa1jpNf22Z+Er3sKwq+w==",
+      "dev": true
+    },
+    "node_modules/pathval": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/pathval/-/pathval-2.0.0.tgz",
+      "integrity": "sha512-vE7JKRyES09KiunauX7nd2Q9/L7lhok4smP9RZTDeD4MVs72Dp2qNFVz39Nz5a0FVEW0BJR6C0DYrq6unoziZA==",
+      "dev": true,
+      "engines": {
+        "node": ">= 14.16"
+      }
+    },
+    "node_modules/picocolors": {
+      "version": "1.1.1",
+      "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz",
+      "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==",
+      "dev": true
+    },
+    "node_modules/picomatch": {
+      "version": "4.0.2",
+      "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.2.tgz",
+      "integrity": "sha512-M7BAV6Rlcy5u+m6oPhAPFgJTzAioX/6B0DxyvDlo9l8+T3nLKbrczg2WLUyzd45L8RqfUMyGPzekbMvX2Ldkwg==",
+      "dev": true,
+      "engines": {
+        "node": ">=12"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/jonschlinkert"
+      }
+    },
+    "node_modules/pirates": {
+      "version": "4.0.6",
+      "resolved": "https://registry.npmjs.org/pirates/-/pirates-4.0.6.tgz",
+      "integrity": "sha512-saLsH7WeYYPiD25LDuLRRY/i+6HaPYr6G1OUlN39otzkSTxKnubR9RTxS3/Kk50s1g2JTgFwWQDQyplC5/SHZg==",
+      "dev": true,
+      "engines": {
+        "node": ">= 6"
+      }
+    },
+    "node_modules/platform": {
+      "version": "1.3.6",
+      "resolved": "https://registry.npmjs.org/platform/-/platform-1.3.6.tgz",
+      "integrity": "sha512-fnWVljUchTro6RiCFvCXBbNhJc2NijN7oIQxbwsyL0buWJPG85v81ehlHI9fXrJsMNgTofEoWIQeClKpgxFLrg=="
+    },
+    "node_modules/postcss": {
+      "version": "8.5.1",
+      "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.1.tgz",
+      "integrity": "sha512-6oz2beyjc5VMn/KV1pPw8fliQkhBXrVn1Z3TVyqZxU8kZpzEKhBdmCFqI6ZbmGtamQvQGuU1sgPTk8ZrXDD7jQ==",
+      "dev": true,
+      "funding": [
+        {
+          "type": "opencollective",
+          "url": "https://opencollective.com/postcss/"
+        },
+        {
+          "type": "tidelift",
+          "url": "https://tidelift.com/funding/github/npm/postcss"
+        },
+        {
+          "type": "github",
+          "url": "https://github.com/sponsors/ai"
+        }
+      ],
+      "dependencies": {
+        "nanoid": "^3.3.8",
+        "picocolors": "^1.1.1",
+        "source-map-js": "^1.2.1"
+      },
+      "engines": {
+        "node": "^10 || ^12 || >=14"
+      }
+    },
+    "node_modules/postcss-load-config": {
+      "version": "6.0.1",
+      "resolved": "https://registry.npmjs.org/postcss-load-config/-/postcss-load-config-6.0.1.tgz",
+      "integrity": "sha512-oPtTM4oerL+UXmx+93ytZVN82RrlY/wPUV8IeDxFrzIjXOLF1pN+EmKPLbubvKHT2HC20xXsCAH2Z+CKV6Oz/g==",
+      "dev": true,
+      "funding": [
+        {
+          "type": "opencollective",
+          "url": "https://opencollective.com/postcss/"
+        },
+        {
+          "type": "github",
+          "url": "https://github.com/sponsors/ai"
+        }
+      ],
+      "dependencies": {
+        "lilconfig": "^3.1.1"
+      },
+      "engines": {
+        "node": ">= 18"
+      },
+      "peerDependencies": {
+        "jiti": ">=1.21.0",
+        "postcss": ">=8.0.9",
+        "tsx": "^4.8.1",
+        "yaml": "^2.4.2"
+      },
+      "peerDependenciesMeta": {
+        "jiti": {
+          "optional": true
+        },
+        "postcss": {
+          "optional": true
+        },
+        "tsx": {
+          "optional": true
+        },
+        "yaml": {
+          "optional": true
+        }
+      }
+    },
+    "node_modules/punycode": {
+      "version": "2.3.1",
+      "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz",
+      "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==",
+      "dev": true,
+      "engines": {
+        "node": ">=6"
+      }
+    },
+    "node_modules/punycode.js": {
+      "version": "2.3.1",
+      "resolved": "https://registry.npmjs.org/punycode.js/-/punycode.js-2.3.1.tgz",
+      "integrity": "sha512-uxFIHU0YlHYhDQtV4R9J6a52SLx28BCjT+4ieh7IGbgwVJWO+km431c4yRlREUAsAmt/uMjQUyQHNEPf0M39CA==",
+      "dev": true,
+      "engines": {
+        "node": ">=6"
+      }
+    },
+    "node_modules/readdirp": {
+      "version": "4.1.1",
+      "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-4.1.1.tgz",
+      "integrity": "sha512-h80JrZu/MHUZCyHu5ciuoI0+WxsCxzxJTILn6Fs8rxSnFPh+UVHYfeIxK1nVGugMqkfC4vJcBOYbkfkwYK0+gw==",
+      "dev": true,
+      "engines": {
+        "node": ">= 14.18.0"
+      },
+      "funding": {
+        "type": "individual",
+        "url": "https://paulmillr.com/funding/"
+      }
+    },
+    "node_modules/resolve-from": {
+      "version": "5.0.0",
+      "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz",
+      "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==",
+      "dev": true,
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/resolve-pkg-maps": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/resolve-pkg-maps/-/resolve-pkg-maps-1.0.0.tgz",
+      "integrity": "sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw==",
+      "dev": true,
+      "funding": {
+        "url": "https://github.com/privatenumber/resolve-pkg-maps?sponsor=1"
+      }
+    },
+    "node_modules/rollup": {
+      "version": "4.34.2",
+      "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.34.2.tgz",
+      "integrity": "sha512-sBDUoxZEaqLu9QeNalL8v3jw6WjPku4wfZGyTU7l7m1oC+rpRihXc/n/H+4148ZkGz5Xli8CHMns//fFGKvpIQ==",
+      "dev": true,
+      "dependencies": {
+        "@types/estree": "1.0.6"
+      },
+      "bin": {
+        "rollup": "dist/bin/rollup"
+      },
+      "engines": {
+        "node": ">=18.0.0",
+        "npm": ">=8.0.0"
+      },
+      "optionalDependencies": {
+        "@rollup/rollup-android-arm-eabi": "4.34.2",
+        "@rollup/rollup-android-arm64": "4.34.2",
+        "@rollup/rollup-darwin-arm64": "4.34.2",
+        "@rollup/rollup-darwin-x64": "4.34.2",
+        "@rollup/rollup-freebsd-arm64": "4.34.2",
+        "@rollup/rollup-freebsd-x64": "4.34.2",
+        "@rollup/rollup-linux-arm-gnueabihf": "4.34.2",
+        "@rollup/rollup-linux-arm-musleabihf": "4.34.2",
+        "@rollup/rollup-linux-arm64-gnu": "4.34.2",
+        "@rollup/rollup-linux-arm64-musl": "4.34.2",
+        "@rollup/rollup-linux-loongarch64-gnu": "4.34.2",
+        "@rollup/rollup-linux-powerpc64le-gnu": "4.34.2",
+        "@rollup/rollup-linux-riscv64-gnu": "4.34.2",
+        "@rollup/rollup-linux-s390x-gnu": "4.34.2",
+        "@rollup/rollup-linux-x64-gnu": "4.34.2",
+        "@rollup/rollup-linux-x64-musl": "4.34.2",
+        "@rollup/rollup-win32-arm64-msvc": "4.34.2",
+        "@rollup/rollup-win32-ia32-msvc": "4.34.2",
+        "@rollup/rollup-win32-x64-msvc": "4.34.2",
+        "fsevents": "~2.3.2"
+      }
+    },
+    "node_modules/shebang-command": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz",
+      "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==",
+      "dev": true,
+      "dependencies": {
+        "shebang-regex": "^3.0.0"
+      },
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/shebang-regex": {
+      "version": "3.0.0",
+      "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz",
+      "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==",
+      "dev": true,
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/siginfo": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/siginfo/-/siginfo-2.0.0.tgz",
+      "integrity": "sha512-ybx0WO1/8bSBLEWXZvEd7gMW3Sn3JFlW3TvX1nREbDLRNQNaeNN8WK0meBwPdAaOI7TtRRRJn/Es1zhrrCHu7g==",
+      "dev": true
+    },
+    "node_modules/signal-exit": {
+      "version": "4.1.0",
+      "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz",
+      "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==",
+      "dev": true,
+      "engines": {
+        "node": ">=14"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/isaacs"
+      }
+    },
+    "node_modules/source-map": {
+      "version": "0.8.0-beta.0",
+      "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.8.0-beta.0.tgz",
+      "integrity": "sha512-2ymg6oRBpebeZi9UUNsgQ89bhx01TcTkmNTGnNO88imTmbSgy4nfujrgVEFKWpMTEGA11EDkTt7mqObTPdigIA==",
+      "dev": true,
+      "dependencies": {
+        "whatwg-url": "^7.0.0"
+      },
+      "engines": {
+        "node": ">= 8"
+      }
+    },
+    "node_modules/source-map-js": {
+      "version": "1.2.1",
+      "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz",
+      "integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==",
+      "dev": true,
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/stackback": {
+      "version": "0.0.2",
+      "resolved": "https://registry.npmjs.org/stackback/-/stackback-0.0.2.tgz",
+      "integrity": "sha512-1XMJE5fQo1jGH6Y/7ebnwPOBEkIEnT4QF32d5R1+VXdXveM0IBMJt8zfaxX1P3QhVwrYe+576+jkANtSS2mBbw==",
+      "dev": true
+    },
+    "node_modules/std-env": {
+      "version": "3.8.0",
+      "resolved": "https://registry.npmjs.org/std-env/-/std-env-3.8.0.tgz",
+      "integrity": "sha512-Bc3YwwCB+OzldMxOXJIIvC6cPRWr/LxOp48CdQTOkPyk/t4JWWJbrilwBd7RJzKV8QW7tJkcgAmeuLLJugl5/w==",
+      "dev": true
+    },
+    "node_modules/string-width": {
+      "version": "5.1.2",
+      "resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz",
+      "integrity": "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==",
+      "dev": true,
+      "dependencies": {
+        "eastasianwidth": "^0.2.0",
+        "emoji-regex": "^9.2.2",
+        "strip-ansi": "^7.0.1"
+      },
+      "engines": {
+        "node": ">=12"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
+    "node_modules/string-width-cjs": {
+      "name": "string-width",
+      "version": "4.2.3",
+      "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz",
+      "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==",
+      "dev": true,
+      "dependencies": {
+        "emoji-regex": "^8.0.0",
+        "is-fullwidth-code-point": "^3.0.0",
+        "strip-ansi": "^6.0.1"
+      },
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/string-width-cjs/node_modules/ansi-regex": {
+      "version": "5.0.1",
+      "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz",
+      "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==",
+      "dev": true,
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/string-width-cjs/node_modules/emoji-regex": {
+      "version": "8.0.0",
+      "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz",
+      "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==",
+      "dev": true
+    },
+    "node_modules/string-width-cjs/node_modules/strip-ansi": {
+      "version": "6.0.1",
+      "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz",
+      "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==",
+      "dev": true,
+      "dependencies": {
+        "ansi-regex": "^5.0.1"
+      },
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/strip-ansi": {
+      "version": "7.1.0",
+      "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz",
+      "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==",
+      "dev": true,
+      "dependencies": {
+        "ansi-regex": "^6.0.1"
+      },
+      "engines": {
+        "node": ">=12"
+      },
+      "funding": {
+        "url": "https://github.com/chalk/strip-ansi?sponsor=1"
+      }
+    },
+    "node_modules/strip-ansi-cjs": {
+      "name": "strip-ansi",
+      "version": "6.0.1",
+      "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz",
+      "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==",
+      "dev": true,
+      "dependencies": {
+        "ansi-regex": "^5.0.1"
+      },
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/strip-ansi-cjs/node_modules/ansi-regex": {
+      "version": "5.0.1",
+      "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz",
+      "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==",
+      "dev": true,
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/sucrase": {
+      "version": "3.35.0",
+      "resolved": "https://registry.npmjs.org/sucrase/-/sucrase-3.35.0.tgz",
+      "integrity": "sha512-8EbVDiu9iN/nESwxeSxDKe0dunta1GOlHufmSSXxMD2z2/tMZpDMpvXQGsc+ajGo8y2uYUmixaSRUc/QPoQ0GA==",
+      "dev": true,
+      "dependencies": {
+        "@jridgewell/gen-mapping": "^0.3.2",
+        "commander": "^4.0.0",
+        "glob": "^10.3.10",
+        "lines-and-columns": "^1.1.6",
+        "mz": "^2.7.0",
+        "pirates": "^4.0.1",
+        "ts-interface-checker": "^0.1.9"
+      },
+      "bin": {
+        "sucrase": "bin/sucrase",
+        "sucrase-node": "bin/sucrase-node"
+      },
+      "engines": {
+        "node": ">=16 || 14 >=14.17"
+      }
+    },
+    "node_modules/thenify": {
+      "version": "3.3.1",
+      "resolved": "https://registry.npmjs.org/thenify/-/thenify-3.3.1.tgz",
+      "integrity": "sha512-RVZSIV5IG10Hk3enotrhvz0T9em6cyHBLkH/YAZuKqd8hRkKhSfCGIcP2KUY0EPxndzANBmNllzWPwak+bheSw==",
+      "dev": true,
+      "dependencies": {
+        "any-promise": "^1.0.0"
+      }
+    },
+    "node_modules/thenify-all": {
+      "version": "1.6.0",
+      "resolved": "https://registry.npmjs.org/thenify-all/-/thenify-all-1.6.0.tgz",
+      "integrity": "sha512-RNxQH/qI8/t3thXJDwcstUO4zeqo64+Uy/+sNVRBx4Xn2OX+OZ9oP+iJnNFqplFra2ZUVeKCSa2oVWi3T4uVmA==",
+      "dev": true,
+      "dependencies": {
+        "thenify": ">= 3.1.0 < 4"
+      },
+      "engines": {
+        "node": ">=0.8"
+      }
+    },
+    "node_modules/tinybench": {
+      "version": "2.9.0",
+      "resolved": "https://registry.npmjs.org/tinybench/-/tinybench-2.9.0.tgz",
+      "integrity": "sha512-0+DUvqWMValLmha6lr4kD8iAMK1HzV0/aKnCtWb9v9641TnP/MFb7Pc2bxoxQjTXAErryXVgUOfv2YqNllqGeg==",
+      "dev": true
+    },
+    "node_modules/tinyexec": {
+      "version": "0.3.2",
+      "resolved": "https://registry.npmjs.org/tinyexec/-/tinyexec-0.3.2.tgz",
+      "integrity": "sha512-KQQR9yN7R5+OSwaK0XQoj22pwHoTlgYqmUscPYoknOoWCWfj/5/ABTMRi69FrKU5ffPVh5QcFikpWJI/P1ocHA==",
+      "dev": true
+    },
+    "node_modules/tinyglobby": {
+      "version": "0.2.10",
+      "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.10.tgz",
+      "integrity": "sha512-Zc+8eJlFMvgatPZTl6A9L/yht8QqdmUNtURHaKZLmKBE12hNPSrqNkUp2cs3M/UKmNVVAMFQYSjYIVHDjW5zew==",
+      "dev": true,
+      "dependencies": {
+        "fdir": "^6.4.2",
+        "picomatch": "^4.0.2"
+      },
+      "engines": {
+        "node": ">=12.0.0"
+      }
+    },
+    "node_modules/tinypool": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/tinypool/-/tinypool-1.0.2.tgz",
+      "integrity": "sha512-al6n+QEANGFOMf/dmUMsuS5/r9B06uwlyNjZZql/zv8J7ybHCgoihBNORZCY2mzUuAnomQa2JdhyHKzZxPCrFA==",
+      "dev": true,
+      "engines": {
+        "node": "^18.0.0 || >=20.0.0"
+      }
+    },
+    "node_modules/tinyrainbow": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/tinyrainbow/-/tinyrainbow-2.0.0.tgz",
+      "integrity": "sha512-op4nsTR47R6p0vMUUoYl/a+ljLFVtlfaXkLQmqfLR1qHma1h/ysYk4hEXZ880bf2CYgTskvTa/e196Vd5dDQXw==",
+      "dev": true,
+      "engines": {
+        "node": ">=14.0.0"
+      }
+    },
+    "node_modules/tinyspy": {
+      "version": "3.0.2",
+      "resolved": "https://registry.npmjs.org/tinyspy/-/tinyspy-3.0.2.tgz",
+      "integrity": "sha512-n1cw8k1k0x4pgA2+9XrOkFydTerNcJ1zWCO5Nn9scWHTD+5tp8dghT2x1uduQePZTZgd3Tupf+x9BxJjeJi77Q==",
+      "dev": true,
+      "engines": {
+        "node": ">=14.0.0"
+      }
+    },
+    "node_modules/tr46": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/tr46/-/tr46-1.0.1.tgz",
+      "integrity": "sha512-dTpowEjclQ7Kgx5SdBkqRzVhERQXov8/l9Ft9dVM9fmg0W0KQSVaXX9T4i6twCPNtYiZM53lpSSUAwJbFPOHxA==",
+      "dev": true,
+      "dependencies": {
+        "punycode": "^2.1.0"
+      }
+    },
+    "node_modules/tree-kill": {
+      "version": "1.2.2",
+      "resolved": "https://registry.npmjs.org/tree-kill/-/tree-kill-1.2.2.tgz",
+      "integrity": "sha512-L0Orpi8qGpRG//Nd+H90vFB+3iHnue1zSSGmNOOCh1GLJ7rUKVwV2HvijphGQS2UmhUZewS9VgvxYIdgr+fG1A==",
+      "dev": true,
+      "bin": {
+        "tree-kill": "cli.js"
+      }
+    },
+    "node_modules/ts-interface-checker": {
+      "version": "0.1.13",
+      "resolved": "https://registry.npmjs.org/ts-interface-checker/-/ts-interface-checker-0.1.13.tgz",
+      "integrity": "sha512-Y/arvbn+rrz3JCKl9C4kVNfTfSm2/mEp5FSz5EsZSANGPSlQrpRI5M4PKF+mJnE52jOO90PnPSc3Ur3bTQw0gA==",
+      "dev": true
+    },
+    "node_modules/tsup": {
+      "version": "8.3.6",
+      "resolved": "https://registry.npmjs.org/tsup/-/tsup-8.3.6.tgz",
+      "integrity": "sha512-XkVtlDV/58S9Ye0JxUUTcrQk4S+EqlOHKzg6Roa62rdjL1nGWNUstG0xgI4vanHdfIpjP448J8vlN0oK6XOJ5g==",
+      "dev": true,
+      "dependencies": {
+        "bundle-require": "^5.0.0",
+        "cac": "^6.7.14",
+        "chokidar": "^4.0.1",
+        "consola": "^3.2.3",
+        "debug": "^4.3.7",
+        "esbuild": "^0.24.0",
+        "joycon": "^3.1.1",
+        "picocolors": "^1.1.1",
+        "postcss-load-config": "^6.0.1",
+        "resolve-from": "^5.0.0",
+        "rollup": "^4.24.0",
+        "source-map": "0.8.0-beta.0",
+        "sucrase": "^3.35.0",
+        "tinyexec": "^0.3.1",
+        "tinyglobby": "^0.2.9",
+        "tree-kill": "^1.2.2"
+      },
+      "bin": {
+        "tsup": "dist/cli-default.js",
+        "tsup-node": "dist/cli-node.js"
+      },
+      "engines": {
+        "node": ">=18"
+      },
+      "peerDependencies": {
+        "@microsoft/api-extractor": "^7.36.0",
+        "@swc/core": "^1",
+        "postcss": "^8.4.12",
+        "typescript": ">=4.5.0"
+      },
+      "peerDependenciesMeta": {
+        "@microsoft/api-extractor": {
+          "optional": true
+        },
+        "@swc/core": {
+          "optional": true
+        },
+        "postcss": {
+          "optional": true
+        },
+        "typescript": {
+          "optional": true
+        }
+      }
+    },
+    "node_modules/tsx": {
+      "version": "4.19.2",
+      "resolved": "https://registry.npmjs.org/tsx/-/tsx-4.19.2.tgz",
+      "integrity": "sha512-pOUl6Vo2LUq/bSa8S5q7b91cgNSjctn9ugq/+Mvow99qW6x/UZYwzxy/3NmqoT66eHYfCVvFvACC58UBPFf28g==",
+      "dev": true,
+      "dependencies": {
+        "esbuild": "~0.23.0",
+        "get-tsconfig": "^4.7.5"
+      },
+      "bin": {
+        "tsx": "dist/cli.mjs"
+      },
+      "engines": {
+        "node": ">=18.0.0"
+      },
+      "optionalDependencies": {
+        "fsevents": "~2.3.3"
+      }
+    },
+    "node_modules/tsx/node_modules/@esbuild/aix-ppc64": {
+      "version": "0.23.1",
+      "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.23.1.tgz",
+      "integrity": "sha512-6VhYk1diRqrhBAqpJEdjASR/+WVRtfjpqKuNw11cLiaWpAT/Uu+nokB+UJnevzy/P9C/ty6AOe0dwueMrGh/iQ==",
+      "cpu": [
+        "ppc64"
+      ],
+      "dev": true,
+      "optional": true,
+      "os": [
+        "aix"
+      ],
+      "engines": {
+        "node": ">=18"
+      }
+    },
+    "node_modules/tsx/node_modules/@esbuild/android-arm": {
+      "version": "0.23.1",
+      "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.23.1.tgz",
+      "integrity": "sha512-uz6/tEy2IFm9RYOyvKl88zdzZfwEfKZmnX9Cj1BHjeSGNuGLuMD1kR8y5bteYmwqKm1tj8m4cb/aKEorr6fHWQ==",
+      "cpu": [
+        "arm"
+      ],
+      "dev": true,
+      "optional": true,
+      "os": [
+        "android"
+      ],
+      "engines": {
+        "node": ">=18"
+      }
+    },
+    "node_modules/tsx/node_modules/@esbuild/android-arm64": {
+      "version": "0.23.1",
+      "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.23.1.tgz",
+      "integrity": "sha512-xw50ipykXcLstLeWH7WRdQuysJqejuAGPd30vd1i5zSyKK3WE+ijzHmLKxdiCMtH1pHz78rOg0BKSYOSB/2Khw==",
+      "cpu": [
+        "arm64"
+      ],
+      "dev": true,
+      "optional": true,
+      "os": [
+        "android"
+      ],
+      "engines": {
+        "node": ">=18"
+      }
+    },
+    "node_modules/tsx/node_modules/@esbuild/android-x64": {
+      "version": "0.23.1",
+      "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.23.1.tgz",
+      "integrity": "sha512-nlN9B69St9BwUoB+jkyU090bru8L0NA3yFvAd7k8dNsVH8bi9a8cUAUSEcEEgTp2z3dbEDGJGfP6VUnkQnlReg==",
+      "cpu": [
+        "x64"
+      ],
+      "dev": true,
+      "optional": true,
+      "os": [
+        "android"
+      ],
+      "engines": {
+        "node": ">=18"
+      }
+    },
+    "node_modules/tsx/node_modules/@esbuild/darwin-arm64": {
+      "version": "0.23.1",
+      "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.23.1.tgz",
+      "integrity": "sha512-YsS2e3Wtgnw7Wq53XXBLcV6JhRsEq8hkfg91ESVadIrzr9wO6jJDMZnCQbHm1Guc5t/CdDiFSSfWP58FNuvT3Q==",
+      "cpu": [
+        "arm64"
+      ],
+      "dev": true,
+      "optional": true,
+      "os": [
+        "darwin"
+      ],
+      "engines": {
+        "node": ">=18"
+      }
+    },
+    "node_modules/tsx/node_modules/@esbuild/darwin-x64": {
+      "version": "0.23.1",
+      "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.23.1.tgz",
+      "integrity": "sha512-aClqdgTDVPSEGgoCS8QDG37Gu8yc9lTHNAQlsztQ6ENetKEO//b8y31MMu2ZaPbn4kVsIABzVLXYLhCGekGDqw==",
+      "cpu": [
+        "x64"
+      ],
+      "dev": true,
+      "optional": true,
+      "os": [
+        "darwin"
+      ],
+      "engines": {
+        "node": ">=18"
+      }
+    },
+    "node_modules/tsx/node_modules/@esbuild/freebsd-arm64": {
+      "version": "0.23.1",
+      "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.23.1.tgz",
+      "integrity": "sha512-h1k6yS8/pN/NHlMl5+v4XPfikhJulk4G+tKGFIOwURBSFzE8bixw1ebjluLOjfwtLqY0kewfjLSrO6tN2MgIhA==",
+      "cpu": [
+        "arm64"
+      ],
+      "dev": true,
+      "optional": true,
+      "os": [
+        "freebsd"
+      ],
+      "engines": {
+        "node": ">=18"
+      }
+    },
+    "node_modules/tsx/node_modules/@esbuild/freebsd-x64": {
+      "version": "0.23.1",
+      "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.23.1.tgz",
+      "integrity": "sha512-lK1eJeyk1ZX8UklqFd/3A60UuZ/6UVfGT2LuGo3Wp4/z7eRTRYY+0xOu2kpClP+vMTi9wKOfXi2vjUpO1Ro76g==",
+      "cpu": [
+        "x64"
+      ],
+      "dev": true,
+      "optional": true,
+      "os": [
+        "freebsd"
+      ],
+      "engines": {
+        "node": ">=18"
+      }
+    },
+    "node_modules/tsx/node_modules/@esbuild/linux-arm": {
+      "version": "0.23.1",
+      "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.23.1.tgz",
+      "integrity": "sha512-CXXkzgn+dXAPs3WBwE+Kvnrf4WECwBdfjfeYHpMeVxWE0EceB6vhWGShs6wi0IYEqMSIzdOF1XjQ/Mkm5d7ZdQ==",
+      "cpu": [
+        "arm"
+      ],
+      "dev": true,
+      "optional": true,
+      "os": [
+        "linux"
+      ],
+      "engines": {
+        "node": ">=18"
+      }
+    },
+    "node_modules/tsx/node_modules/@esbuild/linux-arm64": {
+      "version": "0.23.1",
+      "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.23.1.tgz",
+      "integrity": "sha512-/93bf2yxencYDnItMYV/v116zff6UyTjo4EtEQjUBeGiVpMmffDNUyD9UN2zV+V3LRV3/on4xdZ26NKzn6754g==",
+      "cpu": [
+        "arm64"
+      ],
+      "dev": true,
+      "optional": true,
+      "os": [
+        "linux"
+      ],
+      "engines": {
+        "node": ">=18"
+      }
+    },
+    "node_modules/tsx/node_modules/@esbuild/linux-ia32": {
+      "version": "0.23.1",
+      "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.23.1.tgz",
+      "integrity": "sha512-VTN4EuOHwXEkXzX5nTvVY4s7E/Krz7COC8xkftbbKRYAl96vPiUssGkeMELQMOnLOJ8k3BY1+ZY52tttZnHcXQ==",
+      "cpu": [
+        "ia32"
+      ],
+      "dev": true,
+      "optional": true,
+      "os": [
+        "linux"
+      ],
+      "engines": {
+        "node": ">=18"
+      }
+    },
+    "node_modules/tsx/node_modules/@esbuild/linux-loong64": {
+      "version": "0.23.1",
+      "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.23.1.tgz",
+      "integrity": "sha512-Vx09LzEoBa5zDnieH8LSMRToj7ir/Jeq0Gu6qJ/1GcBq9GkfoEAoXvLiW1U9J1qE/Y/Oyaq33w5p2ZWrNNHNEw==",
+      "cpu": [
+        "loong64"
+      ],
+      "dev": true,
+      "optional": true,
+      "os": [
+        "linux"
+      ],
+      "engines": {
+        "node": ">=18"
+      }
+    },
+    "node_modules/tsx/node_modules/@esbuild/linux-mips64el": {
+      "version": "0.23.1",
+      "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.23.1.tgz",
+      "integrity": "sha512-nrFzzMQ7W4WRLNUOU5dlWAqa6yVeI0P78WKGUo7lg2HShq/yx+UYkeNSE0SSfSure0SqgnsxPvmAUu/vu0E+3Q==",
+      "cpu": [
+        "mips64el"
+      ],
+      "dev": true,
+      "optional": true,
+      "os": [
+        "linux"
+      ],
+      "engines": {
+        "node": ">=18"
+      }
+    },
+    "node_modules/tsx/node_modules/@esbuild/linux-ppc64": {
+      "version": "0.23.1",
+      "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.23.1.tgz",
+      "integrity": "sha512-dKN8fgVqd0vUIjxuJI6P/9SSSe/mB9rvA98CSH2sJnlZ/OCZWO1DJvxj8jvKTfYUdGfcq2dDxoKaC6bHuTlgcw==",
+      "cpu": [
+        "ppc64"
+      ],
+      "dev": true,
+      "optional": true,
+      "os": [
+        "linux"
+      ],
+      "engines": {
+        "node": ">=18"
+      }
+    },
+    "node_modules/tsx/node_modules/@esbuild/linux-riscv64": {
+      "version": "0.23.1",
+      "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.23.1.tgz",
+      "integrity": "sha512-5AV4Pzp80fhHL83JM6LoA6pTQVWgB1HovMBsLQ9OZWLDqVY8MVobBXNSmAJi//Csh6tcY7e7Lny2Hg1tElMjIA==",
+      "cpu": [
+        "riscv64"
+      ],
+      "dev": true,
+      "optional": true,
+      "os": [
+        "linux"
+      ],
+      "engines": {
+        "node": ">=18"
+      }
+    },
+    "node_modules/tsx/node_modules/@esbuild/linux-s390x": {
+      "version": "0.23.1",
+      "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.23.1.tgz",
+      "integrity": "sha512-9ygs73tuFCe6f6m/Tb+9LtYxWR4c9yg7zjt2cYkjDbDpV/xVn+68cQxMXCjUpYwEkze2RcU/rMnfIXNRFmSoDw==",
+      "cpu": [
+        "s390x"
+      ],
+      "dev": true,
+      "optional": true,
+      "os": [
+        "linux"
+      ],
+      "engines": {
+        "node": ">=18"
+      }
+    },
+    "node_modules/tsx/node_modules/@esbuild/linux-x64": {
+      "version": "0.23.1",
+      "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.23.1.tgz",
+      "integrity": "sha512-EV6+ovTsEXCPAp58g2dD68LxoP/wK5pRvgy0J/HxPGB009omFPv3Yet0HiaqvrIrgPTBuC6wCH1LTOY91EO5hQ==",
+      "cpu": [
+        "x64"
+      ],
+      "dev": true,
+      "optional": true,
+      "os": [
+        "linux"
+      ],
+      "engines": {
+        "node": ">=18"
+      }
+    },
+    "node_modules/tsx/node_modules/@esbuild/netbsd-x64": {
+      "version": "0.23.1",
+      "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.23.1.tgz",
+      "integrity": "sha512-aevEkCNu7KlPRpYLjwmdcuNz6bDFiE7Z8XC4CPqExjTvrHugh28QzUXVOZtiYghciKUacNktqxdpymplil1beA==",
+      "cpu": [
+        "x64"
+      ],
+      "dev": true,
+      "optional": true,
+      "os": [
+        "netbsd"
+      ],
+      "engines": {
+        "node": ">=18"
+      }
+    },
+    "node_modules/tsx/node_modules/@esbuild/openbsd-arm64": {
+      "version": "0.23.1",
+      "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.23.1.tgz",
+      "integrity": "sha512-3x37szhLexNA4bXhLrCC/LImN/YtWis6WXr1VESlfVtVeoFJBRINPJ3f0a/6LV8zpikqoUg4hyXw0sFBt5Cr+Q==",
+      "cpu": [
+        "arm64"
+      ],
+      "dev": true,
+      "optional": true,
+      "os": [
+        "openbsd"
+      ],
+      "engines": {
+        "node": ">=18"
+      }
+    },
+    "node_modules/tsx/node_modules/@esbuild/openbsd-x64": {
+      "version": "0.23.1",
+      "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.23.1.tgz",
+      "integrity": "sha512-aY2gMmKmPhxfU+0EdnN+XNtGbjfQgwZj43k8G3fyrDM/UdZww6xrWxmDkuz2eCZchqVeABjV5BpildOrUbBTqA==",
+      "cpu": [
+        "x64"
+      ],
+      "dev": true,
+      "optional": true,
+      "os": [
+        "openbsd"
+      ],
+      "engines": {
+        "node": ">=18"
+      }
+    },
+    "node_modules/tsx/node_modules/@esbuild/sunos-x64": {
+      "version": "0.23.1",
+      "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.23.1.tgz",
+      "integrity": "sha512-RBRT2gqEl0IKQABT4XTj78tpk9v7ehp+mazn2HbUeZl1YMdaGAQqhapjGTCe7uw7y0frDi4gS0uHzhvpFuI1sA==",
+      "cpu": [
+        "x64"
+      ],
+      "dev": true,
+      "optional": true,
+      "os": [
+        "sunos"
+      ],
+      "engines": {
+        "node": ">=18"
+      }
+    },
+    "node_modules/tsx/node_modules/@esbuild/win32-arm64": {
+      "version": "0.23.1",
+      "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.23.1.tgz",
+      "integrity": "sha512-4O+gPR5rEBe2FpKOVyiJ7wNDPA8nGzDuJ6gN4okSA1gEOYZ67N8JPk58tkWtdtPeLz7lBnY6I5L3jdsr3S+A6A==",
+      "cpu": [
+        "arm64"
+      ],
+      "dev": true,
+      "optional": true,
+      "os": [
+        "win32"
+      ],
+      "engines": {
+        "node": ">=18"
+      }
+    },
+    "node_modules/tsx/node_modules/@esbuild/win32-ia32": {
+      "version": "0.23.1",
+      "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.23.1.tgz",
+      "integrity": "sha512-BcaL0Vn6QwCwre3Y717nVHZbAa4UBEigzFm6VdsVdT/MbZ38xoj1X9HPkZhbmaBGUD1W8vxAfffbDe8bA6AKnQ==",
+      "cpu": [
+        "ia32"
+      ],
+      "dev": true,
+      "optional": true,
+      "os": [
+        "win32"
+      ],
+      "engines": {
+        "node": ">=18"
+      }
+    },
+    "node_modules/tsx/node_modules/@esbuild/win32-x64": {
+      "version": "0.23.1",
+      "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.23.1.tgz",
+      "integrity": "sha512-BHpFFeslkWrXWyUPnbKm+xYYVYruCinGcftSBaa8zoF9hZO4BcSCFUvHVTtzpIY6YzUnYtuEhZ+C9iEXjxnasg==",
+      "cpu": [
+        "x64"
+      ],
+      "dev": true,
+      "optional": true,
+      "os": [
+        "win32"
+      ],
+      "engines": {
+        "node": ">=18"
+      }
+    },
+    "node_modules/tsx/node_modules/esbuild": {
+      "version": "0.23.1",
+      "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.23.1.tgz",
+      "integrity": "sha512-VVNz/9Sa0bs5SELtn3f7qhJCDPCF5oMEl5cO9/SSinpE9hbPVvxbd572HH5AKiP7WD8INO53GgfDDhRjkylHEg==",
+      "dev": true,
+      "hasInstallScript": true,
+      "bin": {
+        "esbuild": "bin/esbuild"
+      },
+      "engines": {
+        "node": ">=18"
+      },
+      "optionalDependencies": {
+        "@esbuild/aix-ppc64": "0.23.1",
+        "@esbuild/android-arm": "0.23.1",
+        "@esbuild/android-arm64": "0.23.1",
+        "@esbuild/android-x64": "0.23.1",
+        "@esbuild/darwin-arm64": "0.23.1",
+        "@esbuild/darwin-x64": "0.23.1",
+        "@esbuild/freebsd-arm64": "0.23.1",
+        "@esbuild/freebsd-x64": "0.23.1",
+        "@esbuild/linux-arm": "0.23.1",
+        "@esbuild/linux-arm64": "0.23.1",
+        "@esbuild/linux-ia32": "0.23.1",
+        "@esbuild/linux-loong64": "0.23.1",
+        "@esbuild/linux-mips64el": "0.23.1",
+        "@esbuild/linux-ppc64": "0.23.1",
+        "@esbuild/linux-riscv64": "0.23.1",
+        "@esbuild/linux-s390x": "0.23.1",
+        "@esbuild/linux-x64": "0.23.1",
+        "@esbuild/netbsd-x64": "0.23.1",
+        "@esbuild/openbsd-arm64": "0.23.1",
+        "@esbuild/openbsd-x64": "0.23.1",
+        "@esbuild/sunos-x64": "0.23.1",
+        "@esbuild/win32-arm64": "0.23.1",
+        "@esbuild/win32-ia32": "0.23.1",
+        "@esbuild/win32-x64": "0.23.1"
+      }
+    },
+    "node_modules/typedoc": {
+      "version": "0.27.9",
+      "resolved": "https://registry.npmjs.org/typedoc/-/typedoc-0.27.9.tgz",
+      "integrity": "sha512-/z585740YHURLl9DN2jCWe6OW7zKYm6VoQ93H0sxZ1cwHQEQrUn5BJrEnkWhfzUdyO+BLGjnKUZ9iz9hKloFDw==",
+      "dev": true,
+      "license": "Apache-2.0",
+      "dependencies": {
+        "@gerrit0/mini-shiki": "^1.24.0",
+        "lunr": "^2.3.9",
+        "markdown-it": "^14.1.0",
+        "minimatch": "^9.0.5",
+        "yaml": "^2.6.1"
+      },
+      "bin": {
+        "typedoc": "bin/typedoc"
+      },
+      "engines": {
+        "node": ">= 18"
+      },
+      "peerDependencies": {
+        "typescript": "5.0.x || 5.1.x || 5.2.x || 5.3.x || 5.4.x || 5.5.x || 5.6.x || 5.7.x || 5.8.x"
+      }
+    },
+    "node_modules/typedoc-plugin-markdown": {
+      "version": "4.4.1",
+      "resolved": "https://registry.npmjs.org/typedoc-plugin-markdown/-/typedoc-plugin-markdown-4.4.1.tgz",
+      "integrity": "sha512-fx23nSCvewI9IR8lzIYtzDphETcgTDuxKcmHKGD4lo36oexC+B1k4NaCOY58Snqb4OlE8OXDAGVcQXYYuLRCNw==",
+      "dev": true,
+      "engines": {
+        "node": ">= 18"
+      },
+      "peerDependencies": {
+        "typedoc": "0.27.x"
+      }
+    },
+    "node_modules/typescript": {
+      "version": "5.6.3",
+      "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.6.3.tgz",
+      "integrity": "sha512-hjcS1mhfuyi4WW8IWtjP7brDrG2cuDZukyrYrSauoXGNgx0S7zceP07adYkJycEr56BOUTNPzbInooiN3fn1qw==",
+      "dev": true,
+      "bin": {
+        "tsc": "bin/tsc",
+        "tsserver": "bin/tsserver"
+      },
+      "engines": {
+        "node": ">=14.17"
+      }
+    },
+    "node_modules/uc.micro": {
+      "version": "2.1.0",
+      "resolved": "https://registry.npmjs.org/uc.micro/-/uc.micro-2.1.0.tgz",
+      "integrity": "sha512-ARDJmphmdvUk6Glw7y9DQ2bFkKBHwQHLi2lsaH6PPmz/Ka9sFOBsBluozhDltWmnv9u/cF6Rt87znRTPV+yp/A==",
+      "dev": true
+    },
+    "node_modules/undici-types": {
+      "version": "6.20.0",
+      "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.20.0.tgz",
+      "integrity": "sha512-Ny6QZ2Nju20vw1SRHe3d9jVu6gJ+4e3+MMpqu7pqE5HT6WsTSlce++GQmK5UXS8mzV8DSYHrQH+Xrf2jVcuKNg==",
+      "dev": true,
+      "license": "MIT"
+    },
+    "node_modules/vite": {
+      "version": "6.1.0",
+      "resolved": "https://registry.npmjs.org/vite/-/vite-6.1.0.tgz",
+      "integrity": "sha512-RjjMipCKVoR4hVfPY6GQTgveinjNuyLw+qruksLDvA5ktI1150VmcMBKmQaEWJhg/j6Uaf6dNCNA0AfdzUb/hQ==",
+      "dev": true,
+      "dependencies": {
+        "esbuild": "^0.24.2",
+        "postcss": "^8.5.1",
+        "rollup": "^4.30.1"
+      },
+      "bin": {
+        "vite": "bin/vite.js"
+      },
+      "engines": {
+        "node": "^18.0.0 || ^20.0.0 || >=22.0.0"
+      },
+      "funding": {
+        "url": "https://github.com/vitejs/vite?sponsor=1"
+      },
+      "optionalDependencies": {
+        "fsevents": "~2.3.3"
+      },
+      "peerDependencies": {
+        "@types/node": "^18.0.0 || ^20.0.0 || >=22.0.0",
+        "jiti": ">=1.21.0",
+        "less": "*",
+        "lightningcss": "^1.21.0",
+        "sass": "*",
+        "sass-embedded": "*",
+        "stylus": "*",
+        "sugarss": "*",
+        "terser": "^5.16.0",
+        "tsx": "^4.8.1",
+        "yaml": "^2.4.2"
+      },
+      "peerDependenciesMeta": {
+        "@types/node": {
+          "optional": true
+        },
+        "jiti": {
+          "optional": true
+        },
+        "less": {
+          "optional": true
+        },
+        "lightningcss": {
+          "optional": true
+        },
+        "sass": {
+          "optional": true
+        },
+        "sass-embedded": {
+          "optional": true
+        },
+        "stylus": {
+          "optional": true
+        },
+        "sugarss": {
+          "optional": true
+        },
+        "terser": {
+          "optional": true
+        },
+        "tsx": {
+          "optional": true
+        },
+        "yaml": {
+          "optional": true
+        }
+      }
+    },
+    "node_modules/vite-node": {
+      "version": "3.0.5",
+      "resolved": "https://registry.npmjs.org/vite-node/-/vite-node-3.0.5.tgz",
+      "integrity": "sha512-02JEJl7SbtwSDJdYS537nU6l+ktdvcREfLksk/NDAqtdKWGqHl+joXzEubHROmS3E6pip+Xgu2tFezMu75jH7A==",
+      "dev": true,
+      "dependencies": {
+        "cac": "^6.7.14",
+        "debug": "^4.4.0",
+        "es-module-lexer": "^1.6.0",
+        "pathe": "^2.0.2",
+        "vite": "^5.0.0 || ^6.0.0"
+      },
+      "bin": {
+        "vite-node": "vite-node.mjs"
+      },
+      "engines": {
+        "node": "^18.0.0 || ^20.0.0 || >=22.0.0"
+      },
+      "funding": {
+        "url": "https://opencollective.com/vitest"
+      }
+    },
+    "node_modules/vitest": {
+      "version": "3.0.5",
+      "resolved": "https://registry.npmjs.org/vitest/-/vitest-3.0.5.tgz",
+      "integrity": "sha512-4dof+HvqONw9bvsYxtkfUp2uHsTN9bV2CZIi1pWgoFpL1Lld8LA1ka9q/ONSsoScAKG7NVGf2stJTI7XRkXb2Q==",
+      "dev": true,
+      "dependencies": {
+        "@vitest/expect": "3.0.5",
+        "@vitest/mocker": "3.0.5",
+        "@vitest/pretty-format": "^3.0.5",
+        "@vitest/runner": "3.0.5",
+        "@vitest/snapshot": "3.0.5",
+        "@vitest/spy": "3.0.5",
+        "@vitest/utils": "3.0.5",
+        "chai": "^5.1.2",
+        "debug": "^4.4.0",
+        "expect-type": "^1.1.0",
+        "magic-string": "^0.30.17",
+        "pathe": "^2.0.2",
+        "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.5",
+        "why-is-node-running": "^2.3.0"
+      },
+      "bin": {
+        "vitest": "vitest.mjs"
+      },
+      "engines": {
+        "node": "^18.0.0 || ^20.0.0 || >=22.0.0"
+      },
+      "funding": {
+        "url": "https://opencollective.com/vitest"
+      },
+      "peerDependencies": {
+        "@edge-runtime/vm": "*",
+        "@types/debug": "^4.1.12",
+        "@types/node": "^18.0.0 || ^20.0.0 || >=22.0.0",
+        "@vitest/browser": "3.0.5",
+        "@vitest/ui": "3.0.5",
+        "happy-dom": "*",
+        "jsdom": "*"
+      },
+      "peerDependenciesMeta": {
+        "@edge-runtime/vm": {
+          "optional": true
+        },
+        "@types/debug": {
+          "optional": true
+        },
+        "@types/node": {
+          "optional": true
+        },
+        "@vitest/browser": {
+          "optional": true
+        },
+        "@vitest/ui": {
+          "optional": true
+        },
+        "happy-dom": {
+          "optional": true
+        },
+        "jsdom": {
+          "optional": true
+        }
+      }
+    },
+    "node_modules/webidl-conversions": {
+      "version": "4.0.2",
+      "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-4.0.2.tgz",
+      "integrity": "sha512-YQ+BmxuTgd6UXZW3+ICGfyqRyHXVlD5GtQr5+qjiNW7bF0cqrzX500HVXPBOvgXb5YnzDd+h0zqyv61KUD7+Sg==",
+      "dev": true
+    },
+    "node_modules/whatwg-url": {
+      "version": "7.1.0",
+      "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-7.1.0.tgz",
+      "integrity": "sha512-WUu7Rg1DroM7oQvGWfOiAK21n74Gg+T4elXEQYkOhtyLeWiJFoOGLXPKI/9gzIie9CtwVLm8wtw6YJdKyxSjeg==",
+      "dev": true,
+      "dependencies": {
+        "lodash.sortby": "^4.7.0",
+        "tr46": "^1.0.1",
+        "webidl-conversions": "^4.0.2"
+      }
+    },
+    "node_modules/which": {
+      "version": "2.0.2",
+      "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz",
+      "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==",
+      "dev": true,
+      "dependencies": {
+        "isexe": "^2.0.0"
+      },
+      "bin": {
+        "node-which": "bin/node-which"
+      },
+      "engines": {
+        "node": ">= 8"
+      }
+    },
+    "node_modules/why-is-node-running": {
+      "version": "2.3.0",
+      "resolved": "https://registry.npmjs.org/why-is-node-running/-/why-is-node-running-2.3.0.tgz",
+      "integrity": "sha512-hUrmaWBdVDcxvYqnyh09zunKzROWjbZTiNy8dBEjkS7ehEDQibXJ7XvlmtbwuTclUiIyN+CyXQD4Vmko8fNm8w==",
+      "dev": true,
+      "dependencies": {
+        "siginfo": "^2.0.0",
+        "stackback": "0.0.2"
+      },
+      "bin": {
+        "why-is-node-running": "cli.js"
+      },
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/wrap-ansi": {
+      "version": "8.1.0",
+      "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-8.1.0.tgz",
+      "integrity": "sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==",
+      "dev": true,
+      "dependencies": {
+        "ansi-styles": "^6.1.0",
+        "string-width": "^5.0.1",
+        "strip-ansi": "^7.0.1"
+      },
+      "engines": {
+        "node": ">=12"
+      },
+      "funding": {
+        "url": "https://github.com/chalk/wrap-ansi?sponsor=1"
+      }
+    },
+    "node_modules/wrap-ansi-cjs": {
+      "name": "wrap-ansi",
+      "version": "7.0.0",
+      "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz",
+      "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==",
+      "dev": true,
+      "dependencies": {
+        "ansi-styles": "^4.0.0",
+        "string-width": "^4.1.0",
+        "strip-ansi": "^6.0.0"
+      },
+      "engines": {
+        "node": ">=10"
+      },
+      "funding": {
+        "url": "https://github.com/chalk/wrap-ansi?sponsor=1"
+      }
+    },
+    "node_modules/wrap-ansi-cjs/node_modules/ansi-regex": {
+      "version": "5.0.1",
+      "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz",
+      "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==",
+      "dev": true,
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/wrap-ansi-cjs/node_modules/ansi-styles": {
+      "version": "4.3.0",
+      "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
+      "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
+      "dev": true,
+      "dependencies": {
+        "color-convert": "^2.0.1"
+      },
+      "engines": {
+        "node": ">=8"
+      },
+      "funding": {
+        "url": "https://github.com/chalk/ansi-styles?sponsor=1"
+      }
+    },
+    "node_modules/wrap-ansi-cjs/node_modules/emoji-regex": {
+      "version": "8.0.0",
+      "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz",
+      "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==",
+      "dev": true
+    },
+    "node_modules/wrap-ansi-cjs/node_modules/string-width": {
+      "version": "4.2.3",
+      "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz",
+      "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==",
+      "dev": true,
+      "dependencies": {
+        "emoji-regex": "^8.0.0",
+        "is-fullwidth-code-point": "^3.0.0",
+        "strip-ansi": "^6.0.1"
+      },
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/wrap-ansi-cjs/node_modules/strip-ansi": {
+      "version": "6.0.1",
+      "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz",
+      "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==",
+      "dev": true,
+      "dependencies": {
+        "ansi-regex": "^5.0.1"
+      },
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/yaml": {
+      "version": "2.7.0",
+      "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.7.0.tgz",
+      "integrity": "sha512-+hSoy/QHluxmC9kCIJyL/uyFmLmc+e5CFR5Wa+bpIhIj85LVb9ZH2nVnqrHoSvKogwODv0ClqZkmiSSaIH5LTA==",
+      "dev": true,
+      "bin": {
+        "yaml": "bin.mjs"
+      },
+      "engines": {
+        "node": ">= 14"
+      }
+    }
+  }
+}
diff --git a/packages/js-sdk/package.json b/packages/js-sdk/package.json
index 4c81364..a37f16a 100644
--- a/packages/js-sdk/package.json
+++ b/packages/js-sdk/package.json
@@ -51,11 +51,12 @@
     "generate-ref": "./scripts/generate_sdk_ref.sh"
   },
   "devDependencies": {
+    "@types/node": "^22.13.9",
     "dotenv": "^16.4.5",
-    "typedoc": "^0.26.8",
-    "typedoc-plugin-markdown": "^4.2.7",
     "tsup": "^8.3.5",
     "tsx": "^4.19.2",
+    "typedoc": "^0.27.9",
+    "typedoc-plugin-markdown": "^4.2.7",
     "typescript": "^5.6.3",
     "vitest": "^3.0.5"
   },
diff --git a/packages/js-sdk/src/sandbox.ts b/packages/js-sdk/src/sandbox.ts
index af68a45..f8d737e 100644
--- a/packages/js-sdk/src/sandbox.ts
+++ b/packages/js-sdk/src/sandbox.ts
@@ -1,48 +1,89 @@
-import { Sandbox as SandboxBase, SandboxOpts as SandboxOptsBase, ConnectionConfig } from 'e2b'
-import { generateRandomId } from './utils'
-// import { extractText } from './ocr'
+import { Sandbox as SandboxBase, SandboxOpts as SandboxOptsBase, CommandHandle, CommandResult, CommandExitError, ConnectionConfig, TimeoutError } from 'e2b'
 
+import { generateRandomString } from './utils'
+
+
+interface CursorPosition {
+  x: number;
+  y: number;
+}
+
+interface ScreenSize {
+  width: number;
+  height: number;
+}
+
+/**
+ * Configuration options for the Sandbox environment.
+ * @interface SandboxOpts
+ * @extends {SandboxOptsBase}
+ */
 export interface SandboxOpts extends SandboxOptsBase {
-  videoStream?: boolean
-  onVideoStreamStart?: (url: string) => void
+  /**
+   * The screen resolution in pixels, specified as [width, height].
+   * @type {[number, number]}
+   */
+  resolution?: [number, number]
+
+  /**
+   * Dots per inch (DPI) setting for the display.
+   * @type {number}
+   */
+  dpi?: number
+
+  /**
+   * Display identifier.
+   * @type {string}
+   */
+  display?: string
+
+  /**
+   * Port number for the VNC server.
+   * @type {number}
+   */
+  vncPort?: number
+
+  /**
+   * Port number for the noVNC proxy server.
+   * @type {number}
+   */
+  port?: number
+
+  /**
+   * Whether to enable authentication for noVNC connections.
+   * @type {boolean}
+   */
+  enableAuth?: boolean
 }
 
+
 export class Sandbox extends SandboxBase {
   protected static override readonly defaultTemplate: string = 'desktop'
-  private static readonly streamBaseUrl = 'https://e2b.dev'
-  private videoStreamToken?: string
-
-  private static async startVideoStream(sandbox: Sandbox, apiKey: string, sandboxId: string, onVideoStreamStart?: (url: string) => void) {
-    // First we need to get the stream key
-    const response = await fetch(`${this.streamBaseUrl}/api/stream/sandbox`, {
-      method: 'POST',
-      headers: {
-        'Content-Type': 'application/json',
-        'X-API-Key': apiKey
-      },
-      body: JSON.stringify({
-        sandboxId,
-      })
-    })
-
-    if (!response.ok) {
-      throw new Error(`Failed to start video stream: ${response.statusText}`)
-    }
+  private lastXfce4Pid: number | null = null;
+  readonly display: string;
+  readonly stream: VNCServer;
+  private readonly changeWallpaperCmd: string = (
+    `xfconf-query --create -t string -c xfce4-desktop -p ` +
+    `/backdrop/screen0/monitorscreen/workspace0/last-image -s /usr/share/backgrounds/xfce/wallpaper.png`
+  )
 
-    const data: { streamKey: string, token: string } = await response.json()
-    sandbox.videoStreamToken = data.token
-
-    const command = 'ffmpeg -video_size 1024x768 -f x11grab -i :99 -c:v libx264 -c:a aac -g 50 -b:v 4000k -maxrate 4000k -bufsize 8000k -f flv rtmp://global-live.mux.com:5222/app/$STREAM_KEY'
-    await sandbox.commands.run(command, {
-      background: true,
-      envs: {
-        STREAM_KEY: data.streamKey
-      },
-    })
-    const url = await sandbox.getVideoStreamUrl()
-    onVideoStreamStart?.(url)
+  /**
+   * Use {@link Sandbox.create} to create a new Sandbox instead.
+   *
+   * @hidden
+   * @hide
+   * @internal
+   * @access protected
+   */
+  constructor(opts: Omit<SandboxOpts, 'timeoutMs' | 'envs' | 'metadata'> & {
+    sandboxId: string;
+    envdVersion?: string;
+  }) {
+    super(opts);
+    this.display = opts.display || ':0';
+    this.lastXfce4Pid = null;
+    this.stream = new VNCServer(this);
   }
-
   /**
    * Create a new sandbox from the default `desktop` sandbox template.
    *
@@ -93,46 +134,85 @@ export class Sandbox extends SandboxBase {
 
     let sbx
     if (config.debug) {
-      sbx = new this({ sandboxId: 'debug_sandbox_id', ...config }) as InstanceType<S>
+      sbx = new this({ sandboxId: 'desktop', ...sandboxOpts, ...config }) as InstanceType<S>
     } else {
       const sandbox = await this.createSandbox(
-          template,
-          sandboxOpts?.timeoutMs ?? this.defaultSandboxTimeoutMs,
-          sandboxOpts
+        template,
+        sandboxOpts?.timeoutMs ?? this.defaultSandboxTimeoutMs,
+        sandboxOpts
       )
-      sbx = new this({ ...sandbox, ...config }) as InstanceType<S>
+      sbx = new this({ ...sandbox, ...sandboxOpts, ...config }) as InstanceType<S>
     }
 
-
-    if (sandboxOpts?.videoStream) {
-      this.startVideoStream(sbx, config.apiKey!, sbx.sandboxId, sandboxOpts?.onVideoStreamStart)
+    const [width, height] = sandboxOpts?.resolution ?? [1024, 768]
+    await sbx.commands.run(
+      `Xvfb ${sbx.display} -ac -screen 0 ${width}x${height}x24 ` +
+      `-retro -dpi ${sandboxOpts?.dpi ?? 96} -nolisten tcp -nolisten unix`,
+      { background: true }
+    )
+
+    let hasStarted = await sbx.waitAndVerify(
+      `xdpyinfo -display ${sbx.display}`, (r: CommandResult) => r.exitCode === 0
+    )
+    if (!hasStarted) {
+      throw new TimeoutError("Could not start Xvfb")
     }
 
+    await sbx.startXfce4()
+
     return sbx
   }
 
-  async getVideoStreamUrl() {
-    // We already have the token
-    if (this.videoStreamToken) {
-      return `${Sandbox.streamBaseUrl}/stream/sandbox/${this.sandboxId}?token=${this.videoStreamToken}`
-    }
-
-    // In cases like when a user reconnects to the sandbox, we don't have the token yet and need to get it from the server
-    const response = await fetch(`${Sandbox.streamBaseUrl}/api/stream/sandbox/${this.sandboxId}`, {
-      method: 'GET',
-      headers: {
-        'X-API-Key': this.connectionConfig.apiKey!
+  /**
+   * Wait for a command to return a specific result.
+   * @param cmd - The command to run.
+   * @param onResult - The function to check the result of the command.
+   * @param timeout - The maximum time to wait for the command to return the result.
+   * @param interval - The interval to wait between checks.
+   * @returns `true` if the command returned the result within the timeout, otherwise `false`.
+   */
+  async waitAndVerify(
+    cmd: string,
+    onResult: (result: CommandResult) => boolean,
+    timeout: number = 10,
+    interval: number = 0.5
+  ): Promise<boolean> {
+    let elapsed = 0;
+
+    while (elapsed < timeout) {
+      try {
+        if (onResult(await this.commands.run(cmd))) {
+          return true;
+        }
+      } catch (e) {
+        if (e instanceof CommandExitError) {
+          continue;
+        }
+        throw e;
       }
-    })
 
-    if (!response.ok) {
-      throw new Error(`Failed to get stream token: ${response.status} ${response.statusText}`)
+      await new Promise(resolve => setTimeout(resolve, interval * 1000));
+      elapsed += interval;
     }
 
-    const data: { token: string } = await response.json()
-    this.videoStreamToken = data.token
+    return false;
+  }
 
-    return `${Sandbox.streamBaseUrl}/stream/sandbox/${this.sandboxId}?token=${this.videoStreamToken}`
+  /**
+   * Start xfce4 session if logged out or not running.
+   */
+  private async startXfce4(): Promise<void> {
+    if (this.lastXfce4Pid === null || (
+      await this.commands.run(
+        `ps aux | grep ${this.lastXfce4Pid} | grep -v grep | head -n 1`
+      )).stdout.trim().includes("[xfce4-session] <defunct>")
+    ) {
+      const result = await this.commands.run(
+        "startxfce4", { envs: { DISPLAY: this.display }, background: true }
+      );
+      this.lastXfce4Pid = result.pid;
+      await this.commands.run(this.changeWallpaperCmd, { envs: { DISPLAY: this.display } });
+    }
   }
 
   /**
@@ -140,26 +220,26 @@ export class Sandbox extends SandboxBase {
    * @param format - The format of the screenshot.
    * @returns A Uint8Array bytes representation of the screenshot.
    */
-  async takeScreenshot(): Promise<Uint8Array>
+  async screenshot(): Promise<Uint8Array>
   /**
    * Take a screenshot and save it to the given name.
    * @param format - The format of the screenshot.
    * @returns A Uint8Array bytes representation of the screenshot.
    */
-  async takeScreenshot(format: 'bytes'): Promise<Uint8Array>
+  async screenshot(format: 'bytes'): Promise<Uint8Array>
   /**
    * Take a screenshot and save it to the given name.
    * @returns A Blob representation of the screenshot.
    */
-  async takeScreenshot(format: 'blob'): Promise<Blob>
+  async screenshot(format: 'blob'): Promise<Blob>
   /**
    * Take a screenshot and save it to the given name.
    * @returns A ReadableStream of bytes representation of the screenshot.
    */
-  async takeScreenshot(format: 'stream'): Promise<ReadableStream<Uint8Array>>
-  async takeScreenshot(format: 'bytes' | 'blob' | 'stream' = 'bytes') {
-    const path = `/tmp/screenshot-${generateRandomId()}.png`
-    await this.commands.run(`scrot --pointer ${path}`)
+  async screenshot(format: 'stream'): Promise<ReadableStream<Uint8Array>>
+  async screenshot(format: 'bytes' | 'blob' | 'stream' = 'bytes') {
+    const path = `/tmp/screenshot-${generateRandomString()}.png`
+    await this.commands.run(`scrot --pointer ${path}`, { envs: { DISPLAY: this.display } })
 
     // @ts-expect-error
     const file = await this.files.read(path, { format })
@@ -170,149 +250,281 @@ export class Sandbox extends SandboxBase {
   /**
    * Left click on the current mouse position.
    */
-  async leftClick() {
-    return this.runPyautoguiCode('pyautogui.click()')
+  async leftClick(): Promise<void> {
+    await this.commands.run("xdotool click 1", { envs: { DISPLAY: this.display } });
   }
 
   /**
    * Double left click on the current mouse position.
    */
-  async doubleClick() {
-    return this.runPyautoguiCode('pyautogui.click(clicks=2, interval=0.25)')
+  async doubleClick(): Promise<void> {
+    await this.commands.run("xdotool click --repeat 2 1", { envs: { DISPLAY: this.display } });
   }
 
   /**
    * Right click on the current mouse position.
    */
-  async rightClick() {
-    return this.runPyautoguiCode('pyautogui.rightClick()')
+  async rightClick(): Promise<void> {
+    await this.commands.run("xdotool click 3", { envs: { DISPLAY: this.display } });
   }
 
   /**
    * Middle click on the current mouse position.
    */
-  async middleClick() {
-    return this.runPyautoguiCode('pyautogui.middleClick()')
+  async middleClick(): Promise<void> {
+    await this.commands.run("xdotool click 2", { envs: { DISPLAY: this.display } });
   }
 
   /**
    * Scroll the mouse wheel by the given amount.
+   * @param direction - The direction to scroll. Can be "up" or "down".
    * @param amount - The amount to scroll.
    */
-  async scroll(amount: number) {
-    return this.runPyautoguiCode(`pyautogui.scroll(${amount})`)
+  async scroll(direction: 'up' | 'down' = 'down', amount: number = 1): Promise<void> {
+    const button = direction === 'up' ? '4' : '5';
+    await this.commands.run(
+      `xdotool click --repeat ${amount} ${button}`, { envs: { DISPLAY: this.display } }
+    );
   }
 
   /**
-   * Write the given text at the current cursor position.
-   * @param text - The text to write.
+   * Move the mouse to the given coordinates.
+   * @param x - The x coordinate.
+   * @param y - The y coordinate.
    */
-  async write(text: string) {
-    return this.runPyautoguiCode(`pyautogui.write(${JSON.stringify(text)})`)
+  async moveMouse(x: number, y: number): Promise<void> {
+    await this.commands.run(
+      `xdotool mousemove --sync ${x} ${y}`, { envs: { DISPLAY: this.display } }
+    );
   }
 
   /**
-   * Press a key.
-   * @param key - The key to press (e.g. "enter", "space", "backspace", etc.).
+   * Get the current cursor position.
+   * @returns A object with the x and y coordinates
+   * @throws Error if cursor position cannot be determined
    */
-  async press(key: string) {
-    return this.runPyautoguiCode(`pyautogui.press(${JSON.stringify(key)})`)
+  async getCursorPosition(): Promise<CursorPosition | null> {
+    const result = await this.commands.run(
+      "xdotool getmouselocation", { envs: { DISPLAY: this.display } }
+    );
+
+    const match = result.stdout.match(/x:(\d+)\s+y:(\d+)/);
+    if (!match) {
+      throw new Error(
+        `Failed to parse cursor position from output: ${result.stdout}`
+      );
+    }
+
+    const [, x, y] = match;
+    if (!x || !y) {
+      throw new Error(`Invalid cursor position values: x=${x}, y=${y}`);
+    }
+
+    return { x: parseInt(x), y: parseInt(y) };
   }
 
   /**
-   * Press a hotkey.
-   * @param keys - The keys to press (e.g. `hotkey("ctrl", "c")` will press Ctrl+C).
+   * Get the current screen size.
+   * @returns An {@link ScreenSize} object
+   * @throws Error if screen size cannot be determined
    */
-  async hotkey(...keys: string[]) {
-    const keysString = keys.map(key => JSON.stringify(key)).join(', ')
-    return this.runPyautoguiCode(`pyautogui.hotkey(${keysString})`)
+  async getScreenSize(): Promise<ScreenSize | null> {
+    const result = await this.commands.run(
+      "xrandr", { envs: { DISPLAY: this.display } }
+    );
+
+    const match = result.stdout.match(/(\d+x\d+)/);
+    if (!match) {
+      throw new Error(
+        `Failed to parse screen size from output: ${result.stdout}`
+      );
+    }
+
+    try {
+      const [width, height] = match[1].split("x").map(val => parseInt(val));
+      return { width, height };
+    } catch (error) {
+      throw new Error(`Invalid screen size format: ${match[1]}`);
+    }
+  }
+
+  private *breakIntoChunks(text: string, n: number): Generator<string> {
+    for (let i = 0; i < text.length; i += n) {
+      yield text.slice(i, i + n);
+    }
+  }
+
+  private quoteString(s: string): string {
+    if (!s) {
+      return "''";
+    }
+
+    if (!/[^\w@%+=:,./-]/.test(s)) {
+      return s;
+    }
+
+    // use single quotes, and put single quotes into double quotes
+    // the string $'b is then quoted as '$'"'"'b'
+    return "'" + s.replace(/'/g, "'\"'\"'") + "'";
   }
 
   /**
-   * Open a file or a URL in the default application.
-   * Note that you'll need to wait for the application to be opened.
-   * @param fileOrUrl - The file or URL to open.
+   * Write the given text at the current cursor position.
+   * @param text - The text to write.
+   * @param options - An object containing the chunk size and delay between each chunk of text.
+   * @param options.chunkSize - The size of each chunk of text to write. Default is 25 characters.
+   * @param options.delayInMs - The delay between each chunk of text. Default is 75 ms.
    */
-  async open(fileOrUrl: string) {
-    return this.commands.run(`xdg-open ${fileOrUrl}`, { background: true })
+  async write(
+    text: string,
+    options: { chunkSize: number, delayInMs: number } = { chunkSize: 25, delayInMs: 75 }
+  ): Promise<void> {
+    const chunks = this.breakIntoChunks(text, options.chunkSize);
+
+    for (const chunk of chunks) {
+      await this.commands.run(
+        `xdotool type --delay ${options.delayInMs} ${this.quoteString(chunk)}`,
+        { envs: { DISPLAY: this.display } }
+      );
+    }
   }
 
   /**
-   * Move the mouse to the given coordinates.
-   * @param x - The x coordinate.
-   * @param y - The y coordinate.
+   * Press a key.
+   * @param key - The key to press (e.g. "enter", "space", "backspace", etc.).
    */
-  async moveMouse(x: number, y: number) {
-    return this.runPyautoguiCode(`pyautogui.moveTo(${x}, ${y})`)
+  async press(key: string): Promise<void> {
+    await this.commands.run(
+      `xdotool key ${key}`, { envs: { DISPLAY: this.display } }
+    );
   }
 
   /**
-   * Get the current mouse position.
-   * @returns An object with `x` and `y` coordinates.
+   * Open a file or a URL in the default application.
+   * @param fileOrUrl - The file or URL to open.
    */
-  async getCursorPosition() {
-    // We save the value to a file because stdout contains warnings about Xauthority.
-    await this.runPyautoguiCode(`
-x, y = pyautogui.position()
-with open("/tmp/cursor_position.txt", "w") as f:
-    f.write(str(x) + " " + str(y))
-`)
-    // pos is like this: 100 200
-    const pos = await this.files.read('/tmp/cursor_position.txt')
-    const [x, y] = pos.split(' ').map(Number)
-    return { x, y }
+  async open(fileOrUrl: string): Promise<void> {
+    await this.commands.run(
+      `xdg-open ${fileOrUrl}`, { background: true, envs: { DISPLAY: this.display } }
+    );
+  }
+}
+
+interface VNCServerOptions {
+  vncPort?: number;
+  port?: number;
+  enableAuth?: boolean;
+}
+
+// Modified VNCServer class
+class VNCServer {
+  private vncPort: number = 5900;
+  private port: number = 6080;
+  private novncAuthEnabled: boolean = false;
+  private url: URL | null = null;
+  private vncHandle: CommandHandle | null = null;
+  private novncHandle: CommandHandle | null = null;
+  private readonly password: string;
+  private vncCommand: string = "";
+  private readonly novncCommand: string;
+  private readonly desktop: Sandbox;
+
+  constructor(desktop: Sandbox) {
+    this.desktop = desktop;
+    this.password = generateRandomString();
+
+    this.novncCommand = (
+      `cd /opt/noVNC/utils && ./novnc_proxy --vnc localhost:${this.vncPort} ` +
+      `--listen ${this.port} --web /opt/noVNC > /tmp/novnc.log 2>&1`
+    );
   }
 
   /**
-   * Get the current screen size.
-   * @returns An object with `width` and `height` properties.
+   * Set the VNC command to start the VNC server.
    */
-  async getScreenSize() {
-    // We save the value to a file because stdout contains warnings about Xauthority.
-    await this.runPyautoguiCode(`
-width, height = pyautogui.size()
-with open("/tmp/size.txt", "w") as f:
-    f.write(str(width) + " " + str(height))
-`)
-    // Size is like this: 100 200
-    const size = await this.files.read('/tmp/size.txt')
-    const [width, height] = size.split(' ').map(Number)
-    return { width, height }
+  private async setVncCommand(): Promise<void> {
+    let pwdFlag = "-nopw";
+    if (this.novncAuthEnabled) {
+      await this.desktop.commands.run("mkdir ~/.vnc");
+      await this.desktop.commands.run(`x11vnc -storepasswd ${this.password} ~/.vnc/passwd`);
+      pwdFlag = "-usepw";
+    }
+
+    this.vncCommand = (
+      `x11vnc -display ${this.desktop.display} -forever -wait 50 -shared ` +
+      `-rfbport ${this.vncPort} ${pwdFlag} 2>/tmp/x11vnc_stderr.log`
+    );
+  }
+
+  private async waitForPort(port: number): Promise<boolean> {
+    return await this.desktop.waitAndVerify(
+      `netstat -tuln | grep ":${port} "`, (r: CommandResult) => r.stdout.trim() !== ""
+    );
   }
 
   /**
-   * Run the given Python code that uses pyautogui.
+   * Get the URL to connect to the VNC server.
+   * @param autoConnect - Whether to automatically connect to the server after opening the URL.
+   * @returns The URL to connect to the VNC server.
    */
-  async runPyautoguiCode(
-    code: string,
-    opts: {
-      onStdout?: (data: string) => void
-      onStderr?: (data: string) => void
-    } = {},
-  ) {
-    const path = `/tmp/code-${generateRandomId()}.py`
-    const wrappedCode = this.wrapPyautoguiCode(code)
-    await this.files.write(path, wrappedCode)
-    const out = await this.commands.run(`python ${path}`, {
-      onStdout: opts.onStdout,
-      onStderr: opts.onStderr,
-    })
+  public getUrl(autoConnect: boolean = true): string {
+    if (this.url === null) {
+      throw new Error('Server is not running');
+    }
 
-    this.files.remove(path)
-    return out
+    let url = new URL(this.url);
+    if (autoConnect) {
+      url.searchParams.set('autoconnect', 'true');
+    }
+    if (this.novncAuthEnabled) {
+      url.searchParams.set("password", this.password);
+    }
+    return url.toString()
   }
 
-  private wrapPyautoguiCode(code: string) {
-    return `
-import pyautogui
-import os
-import Xlib.display
+  /**
+   * Start the VNC server.
+   */
+  public async start(opts: VNCServerOptions = {}): Promise<void> {
+    // If both servers are already running, throw an error.
+    if (this.vncHandle !== null && this.novncHandle !== null) {
+      throw new Error('Server is already running');
+    }
+
+    this.vncPort = opts.vncPort ?? this.vncPort;
+    this.port = opts.port ?? this.port;
+    this.novncAuthEnabled = opts.enableAuth ?? this.novncAuthEnabled;
+    this.url = new URL(`https://${this.desktop.getHost(this.port)}/vnc.html`);
 
-display = Xlib.display.Display(os.environ["DISPLAY"])
-pyautogui._pyautogui_x11._display = display
+    // Stop both servers in case one of them is running.
+    await this.stop();
 
-${code}
-exit(0)
-`
+    if (this.vncCommand === "") {
+      await this.setVncCommand();
+    }
+    this.vncHandle = await this.desktop.commands.run(this.vncCommand, { background: true });
+    if (!await this.waitForPort(this.vncPort)) {
+      throw new Error("Could not start VNC server");
+    }
+
+    this.novncHandle = await this.desktop.commands.run(this.novncCommand, { background: true });
+    if (!await this.waitForPort(this.port)) {
+      throw new Error("Could not start noVNC server");
+    }
+  }
+
+  /**
+   * Stop the VNC server.
+   */
+  public async stop(): Promise<void> {
+    if (this.vncHandle) {
+      await this.vncHandle.kill();
+      this.vncHandle = null;
+    }
+
+    if (this.novncHandle) {
+      await this.novncHandle.kill();
+      this.novncHandle = null;
+    }
   }
 }
diff --git a/packages/js-sdk/src/utils.ts b/packages/js-sdk/src/utils.ts
index f492753..bfc74fb 100644
--- a/packages/js-sdk/src/utils.ts
+++ b/packages/js-sdk/src/utils.ts
@@ -1,13 +1,13 @@
-/**
- * Generate a random ID with 16 characters.
- * @returns A random ID.
- */
-export function generateRandomId() {
-  const characters = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
-  let result = '';
-  for (let i = 0; i < 16; i++) {
-    const randomIndex = Math.floor(Math.random() * characters.length);
-    result += characters[randomIndex];
-  }
-  return result;
-}
+import { randomBytes } from 'crypto';
+
+export function generateRandomString(length: number = 16): string {
+    const characters = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
+    const bytes = randomBytes(length);
+    let result = '';
+
+    for (let i = 0; i < length; i++) {
+        result += characters[bytes[i] % characters.length];
+    }
+
+    return result;
+}
\ No newline at end of file
diff --git a/packages/js-sdk/tests/screen.test.ts b/packages/js-sdk/tests/screen.test.ts
index d238fb6..7310bf1 100644
--- a/packages/js-sdk/tests/screen.test.ts
+++ b/packages/js-sdk/tests/screen.test.ts
@@ -7,6 +7,6 @@ sandboxTest('get screen size', async ({ sandbox }) => {
 })
 
 sandboxTest('take screenshot', async ({ sandbox }) => {
-  const screenshot = await sandbox.takeScreenshot()
+  const screenshot = await sandbox.screenshot()
   expect(screenshot.length).toBeGreaterThan(0)
 })
diff --git a/packages/python-sdk/README.md b/packages/python-sdk/README.md
index b3f7979..749bc3c 100644
--- a/packages/python-sdk/README.md
+++ b/packages/python-sdk/README.md
@@ -1,46 +1,86 @@
-# E2B Desktop Sandbox (beta)
+# E2B Desktop Sandbox - Virtual Computer for Computer Use
 
-E2B Desktop Sandbox is an isolated cloud environment with a desktop-like interface powered by [E2B](https://e2b.dev).
+E2B Desktop Sandbox is a secure virtual desktop ready for Computer Use. Powered by [E2B](https://e2b.dev).
 
-Launching E2B Sandbox takes about 300-500ms. You can customize the desktop environment and preinstall any dependencies you want using our [custom sandbox templates](https://e2b.dev/docs/sandbox-template).
+Each sandbox is isolated from the others and can be customized with any dependencies you want.
 
-![Desktop Sandbox](screenshot.png)
+![Desktop Sandbox](../../readme-assets/screenshot.png)
 
-**Work in progress**
-This repository is a work in progress. We welcome feedback and contributions. Here's the list of features we're working on:
-- [ ] JavaScript SDK
-- [ ] Streaming live desktop
-- [ ] Tests
-- [ ] Docstrings
+### Example app using Computer Use with Anthropic's Claude
+
+Check out the [example open-source app](https://github.com/e2b-dev/secure-computer-use) in a separate repository.
+
+## 🚀 Getting started
 
-## Getting started
 The E2B Desktop Sandbox is built on top of [E2B Sandbox](https://e2b.dev/docs).
 
 ### 1. Get E2B API key
+
 Sign up at [E2B](https://e2b.dev) and get your API key.
 Set environment variable `E2B_API_KEY` with your API key.
 
 ### 2. Install SDK
-**Python**
-```bash
-pip install e2b-desktop
-```
 
-**JavaScript**
 ```bash
-Coming soon
+pip install e2b-desktop
 ```
 
 ### 3. Create Desktop Sandbox
+
 ```python
 from e2b_desktop import Sandbox
 
+# Basic initialization
 desktop = Sandbox()
+
+# With custom configuration
+desktop = Sandbox(
+    display=":0",  # Custom display (defaults to :0)
+    resolution=(1920, 1080),  # Custom resolution
+    dpi=96,  # Custom DPI
+)
 ```
 
 ## Features
 
+### Streaming desktop's screen
+
+```python
+from e2b_desktop import Sandbox
+desktop = Sandbox()
+
+# Start the stream
+desktop.stream.start()
+
+# Get stream URL
+url = desktop.stream.get_url()
+print(url)
+
+# Stop the stream
+desktop.stream.stop()
+```
+
+### Streaming with password protection
+
+```python
+from e2b_desktop import Sandbox
+desktop = Sandbox()
+
+# Start the stream
+desktop.stream.start(
+    enable_auth=True  # Enable authentication with an auto-generated password that will be injected in the stream URL
+)
+
+# Get stream URL
+url = desktop.stream.get_url()
+print(url)
+
+# Stop the stream
+desktop.stream.stop()
+```
+
 ### Mouse control
+
 ```python
 from e2b_desktop import Sandbox
 desktop = Sandbox()
@@ -53,36 +93,38 @@ desktop.scroll(10) # Scroll by the amount. Positive for up, negative for down.
 desktop.mouse_move(100, 200) # Move to x, y coordinates
 ```
 
-### Locate on screen
-```python
-from e2b_desktop import Sandbox
-desktop = Sandbox()
-
-# Find "Home" text on the screen and return the coordinates
-x, y = desktop.locate_on_screen("Home")
-# Move the mouse to the coordinates
-desktop.mouse_move(x, y)
-```
-
 ### Keyboard control
+
 ```python
 from e2b_desktop import Sandbox
 desktop = Sandbox()
 
-desktop.write("Hello, world!") # Write text at the current cursor position
-desktop.hotkey("ctrl", "c") # Press ctrl+c
+# Write text at the current cursor position with customizable typing speed
+desktop.write("Hello, world!")  # Default: chunk_size=25, delay_in_ms=75
+desktop.write("Fast typing!", chunk_size=50, delay_in_ms=25)  # Faster typing
+
+# Press keys
+desktop.press("enter")
+desktop.press("space")
+desktop.press("backspace")
+desktop.press("ctrl+c")
 ```
 
 ### Screenshot
+
 ```python
 from e2b_desktop import Sandbox
 desktop = Sandbox()
 
 # Take a screenshot and save it as "screenshot.png" locally
-desktop.screenshot("screenshot.png")
+image = desktop.screenshot()
+# Save the image to a file
+with open("screenshot.png", "wb") as f:
+    f.write(image)
 ```
 
 ### Open file
+
 ```python
 from e2b_desktop import Sandbox
 desktop = Sandbox()
@@ -93,31 +135,17 @@ desktop.open("/home/user/index.js") # Then open it
 ```
 
 ### Run any bash commands
-```python
-from e2b_desktop import Sandbox
-desktop = Sandbox()
-
-# Run any bash command
-desktop.commands.run("ls -la /home/user")
-```
 
-### Run PyAutoGUI commands
 ```python
 from e2b_desktop import Sandbox
 desktop = Sandbox()
 
-# Run any PyAutoGUI command
-desktop.pyautogui("pyautogui.click()")
+# Run any bash command
+out = desktop.commands.run("ls -la /home/user")
+print(out)
 ```
 
-<!-- ### Customization
-```python
-from e2b_desktop import Sandbox
-desktop = Sandbox()
-``` -->
-
 ## Under the hood
-You can use [PyAutoGUI](https://pyautogui.readthedocs.io/en/latest/) to control the whole environment programmatically.
 
 The desktop-like environment is based on Linux and [Xfce](https://www.xfce.org/) at the moment. We chose Xfce because it's a fast and lightweight environment that's also popular and actively supported. However, this Sandbox template is fully customizable and you can create your own desktop environment.
-Check out the code [here](./template/)
+Check out the sandbox template's code [here](./template/).
diff --git a/packages/python-sdk/e2b_desktop/__init__.py b/packages/python-sdk/e2b_desktop/__init__.py
index 163338b..a642f90 100644
--- a/packages/python-sdk/e2b_desktop/__init__.py
+++ b/packages/python-sdk/e2b_desktop/__init__.py
@@ -1,3 +1,3 @@
 from e2b import *
 
-from .main import Sandbox
+from .main import Sandbox
\ No newline at end of file
diff --git a/packages/python-sdk/e2b_desktop/main.py b/packages/python-sdk/e2b_desktop/main.py
index 6125378..59c028f 100644
--- a/packages/python-sdk/e2b_desktop/main.py
+++ b/packages/python-sdk/e2b_desktop/main.py
@@ -1,115 +1,242 @@
-import uuid
-from typing import Literal, Iterator, overload
+import time
+from re import search as re_search
+from shlex import quote as quote_string
+from typing import Callable, Dict, Iterator, Literal, Optional, overload, Tuple
+from uuid import uuid4
 
-from typing import Callable, Optional
-from e2b import Sandbox as SandboxBase
-import requests
+from e2b import Sandbox as SandboxBase, CommandHandle, CommandResult, TimeoutException, CommandExitException
 
 
-class Sandbox(SandboxBase):
-    default_template = "desktop"
-    stream_base_url = "https://e2b.dev"
+class _VNCServer:
+    def __init__(self, desktop: "Sandbox") -> None:
+        self.__vnc_handle: CommandHandle | None = None
+        self.__novnc_handle: CommandHandle | None = None
+        
+        self._vnc_port = 5900
+        self._port = 6080
+        self._novnc_auth_enabled = False
 
-    @staticmethod
-    def start_video_stream(sandbox: "Sandbox", api_key: str, sandbox_id: str):
-
-        # First we need to get the stream key
-        response = requests.post(
-            f"{Sandbox.stream_base_url}/api/stream/sandbox",
-            headers={
-                "Content-Type": "application/json",
-                "X-API-Key": api_key,
-            },
-            json={"sandboxId": sandbox_id},
-        )
+        self._url = f"https://{desktop.get_host(self._port)}/vnc.html"
 
-        if not response.ok:
-            raise Exception(
-                f"Failed to start video stream {response.status_code}: {response.text}"
-            )
+        self._novnc_password = self._generate_password()
+
+        self.__desktop = desktop
 
-        data = response.json()
-        sandbox.video_stream_token = data["token"]
-        command = (
-            "ffmpeg -video_size 1024x768 -f x11grab -i :99 -c:v libx264 -c:a aac -g 50 "
-            "-b:v 4000k -maxrate 4000k -bufsize 8000k -f flv rtmp://global-live.mux.com:5222/app/$STREAM_KEY"
+    def _wait_for_port(self, port: int) -> bool:
+        return self.__desktop._wait_and_verify(
+            f'netstat -tuln | grep ":{port} "', lambda r: r.stdout.strip() != ""
         )
-        sandbox.commands.run(
-            command,
-            background=True,
-            envs={"STREAM_KEY": data["streamKey"]},
+    
+    @staticmethod
+    def _generate_password(length: int = 16) -> str:
+        import secrets
+        import string
+
+        characters = string.ascii_letters + string.digits
+        return ''.join(secrets.choice(characters) for _ in range(length))
+
+    def get_url(self, auto_connect: bool = True) -> str:
+        params = []
+        if auto_connect:
+            params.append("autoconnect=true")
+        if self._novnc_auth_enabled:
+            params.append(f"password={self._novnc_password}")
+        if params:
+            return f"{self._url}?{'&'.join(params)}"
+        return self._url
+    
+    @property
+    def password(self) -> str:
+        return self._novnc_password
+
+    def start(self, vnc_port: Optional[int] = None, port: Optional[int] = None, enable_auth: bool = False) -> None:
+        # If both servers are already running, throw an error
+        if self.__vnc_handle is not None and self.__novnc_handle is not None:
+            raise RuntimeError('Server is already running')
+
+        # Stop servers in case one of them is running
+        self.stop()
+        
+        # Update parameters if provided
+        self._vnc_port = vnc_port or self._vnc_port
+        self._port = port or self._port
+        self._novnc_auth_enabled = enable_auth or self._novnc_auth_enabled
+        
+        # Update URL with new port
+        self._url = f"https://{self.__desktop.get_host(self._port)}/vnc.html"
+        
+        # Set up VNC command
+        pwd_flag = "-nopw"
+        if self._novnc_auth_enabled:
+            self.__desktop.commands.run("mkdir ~/.vnc")
+            self.__desktop.commands.run(f"x11vnc -storepasswd {self._novnc_password} ~/.vnc/passwd")
+            pwd_flag = "-usepw"
+
+        vnc_command = (
+            f"x11vnc -display {self.__desktop._display} -forever -wait 50 -shared "
+            f"-rfbport {self._vnc_port} {pwd_flag} 2>/tmp/x11vnc_stderr.log"
+        )
+        
+        novnc_command = (
+            f"cd /opt/noVNC/utils && ./novnc_proxy --vnc localhost:{self._vnc_port} "
+            f"--listen {self._port} --web /opt/noVNC > /tmp/novnc.log 2>&1"
         )
 
-    def __init__(self, *args, video_stream=False, **kwargs):
-        super().__init__(*args, **kwargs)
-        if not self._connection_config.api_key:
-            raise ValueError("API key is required")
+        self.__vnc_handle = self.__desktop.commands.run(vnc_command, background=True)
+        if not self._wait_for_port(self._vnc_port):
+            raise TimeoutException("Could not start VNC server")
 
-        if video_stream:
-            self.start_video_stream(
-                self,
-                self._connection_config.api_key,
-                self.sandbox_id,
-            )
+        self.__novnc_handle = self.__desktop.commands.run(novnc_command, background=True)
+        if not self._wait_for_port(self._port):
+            raise TimeoutException("Could not start noVNC server")
 
-    def get_video_stream_url(self):
-        """
-        Get the video stream URL.
-        """
-        # We already have the token
-        if hasattr(self, "video_stream_token") and self.video_stream_token:
-            return f"{self.stream_base_url}/stream/sandbox/{self.sandbox_id}?token={self.video_stream_token}"
+    def stop(self) -> None:
+        if self.__vnc_handle:
+            self.__vnc_handle.kill()
+            self.__vnc_handle = None
+        
+        if self.__novnc_handle:
+            self.__novnc_handle.kill()
+            self.__novnc_handle = None
 
-        # In cases like when a user reconnects to the sandbox, we don't have the token yet and need to get it from the server
-        response = requests.get(
-            f"{self.stream_base_url}/api/stream/sandbox/{self.sandbox_id}",
-            headers={
-                "Content-Type": "application/json",
-                "X-API-Key": self._connection_config.api_key,
-            },
-        )
 
-        if not response.ok:
-            raise Exception(
-                f"Failed to get stream token: {response.status_code} {response.reason}"
-            )
+class Sandbox(SandboxBase):
+    default_template = "desktop"
+    change_wallpaper_cmd = (
+        "xfconf-query --create -t string -c xfce4-desktop -p "
+        "/backdrop/screen0/monitorscreen/workspace0/last-image -s /usr/share/backgrounds/xfce/wallpaper.png"
+    )
+
+    def __init__(
+        self,
+        resolution: Optional[Tuple[int, int]] = None, 
+        dpi: Optional[int] = None,
+        display: Optional[str] = None,
+        template: Optional[str] = None,
+        timeout: Optional[int] = None,
+        metadata: Optional[Dict[str, str]] = None,
+        envs: Optional[Dict[str, str]] = None,
+        api_key: Optional[str] = None,
+        domain: Optional[str] = None,
+        debug: Optional[bool] = None,
+        sandbox_id: Optional[str] = None,
+        request_timeout: Optional[float] = None,
+    ):
+        """
+        Create a new desktop sandbox.
+
+        By default, the sandbox is created from the `desktop` template.
+
+        :param resolution: Startup the desktop with custom screen resolution. Defaults to (1024, 768)
+        :param dpi: Startup the desktop with custom DPI. Defaults to 96
+        :param display: Startup the desktop with custom display. Defaults to ":0"
+        :param template: Sandbox template name or ID
+        :param timeout: Timeout for the sandbox in **seconds**, default to 300 seconds. Maximum time a sandbox can be kept alive is 24 hours (86_400 seconds) for Pro users and 1 hour (3_600 seconds) for Hobby users
+        :param metadata: Custom metadata for the sandbox
+        :param envs: Custom environment variables for the sandbox
+        :param api_key: E2B API Key to use for authentication, defaults to `E2B_API_KEY` environment variable
+        :param domain: E2B domain to use for authentication, defaults to `E2B_DOMAIN` environment variable
+        :param debug: If True, the sandbox will be created in debug mode, defaults to `E2B_DEBUG` environment variable
+        :param sandbox_id: Sandbox ID to connect to, defaults to `E2B_SANDBOX_ID` environment variable
+        :param request_timeout: Timeout for the request in **seconds**
+
+        :return: sandbox instance for the new sandbox
+        """
+        super().__init__(
+            template=template,
+            timeout=timeout,
+            metadata=metadata,
+            envs=envs,
+            api_key=api_key,
+            domain=domain,
+            debug=debug,
+            sandbox_id=sandbox_id,
+            request_timeout=request_timeout,
+        )
+        self._display = display or ":0"
+        self._last_xfce4_pid = None
 
-        data = response.json()
-        self.video_stream_token = data["token"]
+        width, height = resolution or (1024, 768)
+        self.commands.run(
+            f"Xvfb {self._display} -ac -screen 0 {width}x{height}x24"
+            f" -retro -dpi {dpi or 96} -nolisten tcp -nolisten unix",
+            background=True
+        )
 
-        return f"{self.stream_base_url}/stream/sandbox/{self.sandbox_id}?token={self.video_stream_token}"
+        if not self._wait_and_verify(
+            f"xdpyinfo -display {self._display}", lambda r: r.exit_code == 0
+        ):
+            raise TimeoutException("Could not start Xvfb")
+
+        self.__vnc_server = _VNCServer(self)
+        self._start_xfce4()
+
+
+    def _wait_and_verify(
+        self, 
+        cmd: str, 
+        on_result: Callable[[CommandResult], bool],
+        timeout: int = 10,
+        interval: float = 0.5
+    ) -> bool:
+
+        elapsed = 0
+        while elapsed < timeout:
+            try:
+                if on_result(self.commands.run(cmd)):
+                    return True
+            except CommandExitException:
+                continue
+            
+            time.sleep(interval)
+            elapsed += interval
+
+        return False
+    
+    def _start_xfce4(self):
+        """
+        Start xfce4 session if logged out or not running.
+        """
+        if self._last_xfce4_pid is None or "[xfce4-session] <defunct>" in (
+            self.commands.run(f"ps aux | grep {self._last_xfce4_pid} | grep -v grep | head -n 1").stdout.strip()
+        ):
+            self._last_xfce4_pid = self.commands.run(
+                "startxfce4", envs={"DISPLAY": self._display}, background=True
+            ).pid
+            self.commands.run(self.change_wallpaper_cmd, envs={"DISPLAY": self._display})
+
+    @property
+    def stream(self) -> _VNCServer:
+        return self.__vnc_server
 
     @overload
-    def take_screenshot(self, format: Literal["stream"]) -> Iterator[bytes]:
+    def screenshot(self, format: Literal["stream"]) -> Iterator[bytes]:
         """
         Take a screenshot and return it as a stream of bytes.
         """
-        ...
 
     @overload
-    def take_screenshot(
+    def screenshot(
         self,
         format: Literal["bytes"],
     ) -> bytearray:
         """
         Take a screenshot and return it as a bytearray.
         """
-        ...
 
-    def take_screenshot(
+    def screenshot(
         self,
         format: Literal["bytes", "stream"] = "bytes",
     ):
         """
         Take a screenshot and return it in the specified format.
+
         :param format: The format of the screenshot. Can be 'bytes', 'blob', or 'stream'.
         :returns: The screenshot in the specified format.
         """
-        screenshot_path = f"/tmp/screenshot-{uuid.uuid4()}.png"
+        screenshot_path = f"/tmp/screenshot-{uuid4()}.png"
 
-        self.commands.run(
-            f"scrot --pointer {screenshot_path}",
-        )
+        self.commands.run(f"scrot --pointer {screenshot_path}", envs={"DISPLAY": self._display})
 
         file = self.files.read(screenshot_path, format=format)
         self.files.remove(screenshot_path)
@@ -119,133 +246,118 @@ def left_click(self):
         """
         Left click on the current mouse position.
         """
-        return self.pyautogui("pyautogui.click()")
+        self.commands.run("xdotool click 1", envs={"DISPLAY": self._display})
 
     def double_click(self):
         """
         Double left click on the current mouse position.
         """
-        return self.pyautogui("pyautogui.doubleClick()")
+        self.commands.run("xdotool click --repeat 2 1", envs={"DISPLAY": self._display})
 
     def right_click(self):
         """
         Right click on the current mouse position.
         """
-        return self.pyautogui("pyautogui.rightClick()")
+        self.commands.run("xdotool click 3", envs={"DISPLAY": self._display})
 
     def middle_click(self):
         """
         Middle click on the current mouse position.
         """
-        return self.pyautogui("pyautogui.middleClick()")
+        self.commands.run("xdotool click 2", envs={"DISPLAY": self._display})
 
-    def scroll(self, amount: int):
+    def scroll(self, direction: Literal["up", "down"] = "down", amount: int = 1):
         """
         Scroll the mouse wheel by the given amount.
+
+        :param direction: The direction to scroll. Can be "up" or "down".
         :param amount: The amount to scroll.
         """
-        return self.pyautogui(f"pyautogui.scroll({amount})")
+        self.commands.run(
+            f"xdotool click --repeat {amount} {'4' if direction == 'up' else '5'}",
+            envs={"DISPLAY": self._display}
+        )
 
     def move_mouse(self, x: int, y: int):
         """
         Move the mouse to the given coordinates.
+        
         :param x: The x coordinate.
         :param y: The y coordinate.
         """
-        return self.pyautogui(f"pyautogui.moveTo({x}, {y})")
+        self.commands.run(f"xdotool mousemove --sync {x} {y}", envs={"DISPLAY": self._display})
 
-    def get_cursor_position(self):
+    def get_cursor_position(self) -> tuple[int, int]:
         """
         Get the current cursor position.
-        :return: A tuple with the x and y coordinates.
-        """
-        # We save the value to a file because stdout contains warnings about Xauthority.
-        self.pyautogui(
-            """
-x, y = pyautogui.position()
-with open("/tmp/cursor_position.txt", "w") as f:
-    f.write(str(x) + " " + str(y))
-"""
-        )
-        # pos is like this: 100 200
-        pos = self.files.read("/tmp/cursor_position.txt")
-        return tuple(map(int, pos.split(" ")))
 
-    def get_screen_size(self):
+        :return: A tuple with the x and y coordinates
+        :raises RuntimeError: If the cursor position cannot be determined
+        """
+        result = self.commands.run("xdotool getmouselocation", envs={"DISPLAY": self._display})
+            
+        groups = re_search(r"x:(\d+)\s+y:(\d+)", result.stdout)
+        if not groups:
+            raise RuntimeError(f"Failed to parse cursor position from output: {result.stdout}")
+            
+        x, y = groups.group(1), groups.group(2)
+        if not x or not y:
+            raise RuntimeError(f"Invalid cursor position values: x={x}, y={y}")
+            
+        return int(x), int(y)
+        
+    def get_screen_size(self) -> tuple[int, int]:
         """
         Get the current screen size.
-        :return: A tuple with the width and height.
-        """
-        # We save the value to a file because stdout contains warnings about Xauthority.
-        self.pyautogui(
-            """
-width, height = pyautogui.size()
-with open("/tmp/size.txt", "w") as f:
-    f.write(str(width) + " " + str(height))
-"""
-        )
-        # size is like this: 100 200
-        size = self.files.read("/tmp/size.txt")
-        return tuple(map(int, size.split(" ")))
 
-    def write(self, text: str):
+        :return: A tuple with the width and height
+        :raises RuntimeError: If the screen size cannot be determined
+        """
+        result = self.commands.run("xrandr", envs={"DISPLAY": self._display})
+            
+        _match = re_search(r"(\d+x\d+)", result.stdout)
+        if not _match:
+            raise RuntimeError(f"Failed to parse screen size from output: {result.stdout}")
+            
+        try:
+            return tuple(map(int, _match.group(1).split("x")))  # type: ignore
+        except (ValueError, IndexError) as e:
+            raise RuntimeError(f"Invalid screen size format: {_match.group(1)}") from e
+
+    def write(self,        
+        text: str,
+        *,
+        chunk_size: int = 25,
+        delay_in_ms: int = 75
+    ) -> None:
         """
         Write the given text at the current cursor position.
+        
         :param text: The text to write.
+        :param chunk_size: The size of each chunk of text to write.
+        :param delay_in_ms: The delay between each chunk of text.
         """
-        return self.pyautogui(f"pyautogui.write({text!r})")
+        def break_into_chunks(text: str, n: int):
+            for i in range(0, len(text), n):
+                yield text[i : i + n]
+
+        for chunk in break_into_chunks(text, chunk_size):
+            self.commands.run(
+                f"xdotool type --delay {delay_in_ms} {quote_string(chunk)}", envs={"DISPLAY": self._display}
+            )
 
     def press(self, key: str):
         """
         Press a key.
-        :param key: The key to press (e.g. "enter", "space", "backspace", etc.).
-        """
-        return self.pyautogui(f"pyautogui.press({key!r})")
 
-    def hotkey(self, *keys):
-        """
-        Press a hotkey.
-        :param keys: The keys to press (e.g. `hotkey("ctrl", "c")` will press Ctrl+C).
+        :param key: The key to press (e.g. "enter", "space", "backspace", etc.).
         """
-        return self.pyautogui(f"pyautogui.hotkey({keys!r})")
+        self.commands.run(f"xdotool key {key}", envs={"DISPLAY": self._display})
 
     def open(self, file_or_url: str):
         """
         Open a file or a URL in the default application.
+
         :param file_or_url: The file or URL to open.
         """
-        return self.commands.run(f"xdg-open {file_or_url}", background=True)
-
-    @staticmethod
-    def _wrap_pyautogui_code(code: str):
-        return f"""
-import pyautogui
-import os
-import Xlib.display
-
-display = Xlib.display.Display(os.environ["DISPLAY"])
-pyautogui._pyautogui_x11._display = display
-
-{code}
-exit(0)
-"""
-
-    def pyautogui(
-        self,
-        pyautogui_code: str,
-        on_stdout: Optional[Callable[[str], None]] = None,
-        on_stderr: Optional[Callable[[str], None]] = None,
-    ):
-        code_path = f"/tmp/code-{uuid.uuid4()}.py"
-
-        code = self._wrap_pyautogui_code(pyautogui_code)
-
-        self.files.write(code_path, code)
-
-        out = self.commands.run(
-            f"python {code_path}",
-            on_stdout=on_stdout,
-            on_stderr=on_stderr,
-        )
-        self.files.remove(code_path)
-        return out
+        self.commands.run(f"xdg-open {file_or_url}", background=True, envs={"DISPLAY": self._display})
diff --git a/packages/python-sdk/example.py b/packages/python-sdk/example.py
index fc76c3b..a5966af 100644
--- a/packages/python-sdk/example.py
+++ b/packages/python-sdk/example.py
@@ -7,27 +7,29 @@
 load_dotenv()
 
 print("Starting desktop sandbox...")
-desktop = Sandbox(
-    video_stream=True,
-)
-stream_url = desktop.get_video_stream_url()
-print("Video stream URL:", stream_url)
+desktop = Sandbox()
+print("Screen size:", desktop.get_screen_size())
+
+desktop.stream.start(enable_auth=True)
+
+print("Stream URL:", desktop.stream.get_url())
+
+input("Press enter to continue...")
+
 print("Desktop Sandbox started, ID:", desktop.sandbox_id)
 
-screenshot = desktop.take_screenshot(format="bytes")
+screenshot = desktop.screenshot(format="bytes")
+
 with open("1.png", "wb") as f:
     f.write(screenshot)
 
 print("Moving mouse to 'Applications' and clicking...")
 desktop.move_mouse(100, 100)
 desktop.left_click()
-desktop.commands.run(
-    cmd="code /home/user",
-    background=True,
-)
+print("Cursor position:", desktop.get_cursor_position())
 
 time.sleep(1)
-screenshot = desktop.take_screenshot(format="bytes")
+screenshot = desktop.screenshot(format="bytes")
 with open("2.png", "wb") as f:
     f.write(screenshot)
 
@@ -40,4 +42,5 @@
     print("Right clicked", i)
     time.sleep(2)
 
+desktop.stream.stop()
 desktop.kill()
diff --git a/packages/python-sdk/index.html b/packages/python-sdk/index.html
deleted file mode 100644
index dd26920..0000000
--- a/packages/python-sdk/index.html
+++ /dev/null
@@ -1,76 +0,0 @@
-<!DOCTYPE html>
-<html lang="en">
-<head>
-    <meta charset="UTF-8">
-    <meta name="viewport" content="width=device-width, initial-scale=1.0">
-    <title>Mux Stream Viewer</title>
-    <script src="https://cdn.jsdelivr.net/npm/hls.js@latest"></script>
-    <style>
-        body {
-            font-family: Arial, sans-serif;
-            display: flex;
-            flex-direction: column;
-            align-items: center;
-            padding: 20px;
-        }
-        #playbackIdInput {
-            margin: 10px 0;
-            padding: 5px;
-            width: 300px;
-        }
-        #loadStream {
-            padding: 5px 10px;
-            cursor: pointer;
-        }
-        #videoContainer {
-            margin-top: 20px;
-        }
-        video {
-            max-width: 100%;
-            height: auto;
-        }
-    </style>
-</head>
-<body>
-    <h1>Mux Stream Viewer</h1>
-    <input type="text" id="playbackIdInput" placeholder="Enter Playback ID">
-    <button id="loadStream">Load Stream</button>
-    <div id="videoContainer">
-        <video id="video" controls></video>
-    </div>
-
-    <script>
-        const video = document.getElementById('video');
-        const playbackIdInput = document.getElementById('playbackIdInput');
-        const loadStreamButton = document.getElementById('loadStream');
-
-        loadStreamButton.addEventListener('click', loadStream);
-
-        function loadStream() {
-            const playbackId = playbackIdInput.value.trim();
-            if (!playbackId) {
-                alert('Please enter a Playback ID');
-                return;
-            }
-
-            const sourceUrl = `https://stream.mux.com/${playbackId}.m3u8`;
-
-            if (Hls.isSupported()) {
-                const hls = new Hls();
-                hls.loadSource(sourceUrl);
-                hls.attachMedia(video);
-                hls.on(Hls.Events.MANIFEST_PARSED, function() {
-                    video.play();
-                });
-            } else if (video.canPlayType('application/vnd.apple.mpegurl')) {
-                video.src = sourceUrl;
-                video.addEventListener('loadedmetadata', function() {
-                    video.play();
-                });
-            } else {
-                alert('HLS is not supported in your browser');
-            }
-        }
-    </script>
-</body>
-</html>
\ No newline at end of file
diff --git a/packages/python-sdk/package.json b/packages/python-sdk/package.json
index ab6376c..9cabc4e 100644
--- a/packages/python-sdk/package.json
+++ b/packages/python-sdk/package.json
@@ -11,4 +11,4 @@
     "pretest": "poetry install",
     "generate-ref": "poetry install && ./scripts/generate_sdk_ref.sh"
   }
-}
+}
\ No newline at end of file
diff --git a/packages/python-sdk/tests/test_controls.py b/packages/python-sdk/tests/test_controls.py
index 22cd706..a4f97f4 100644
--- a/packages/python-sdk/tests/test_controls.py
+++ b/packages/python-sdk/tests/test_controls.py
@@ -17,7 +17,7 @@ def images_are_equal(img1, img2):
 
 def test_right_click(sandbox: Sandbox):
     # Capture the initial screenshot
-    initial_screenshot_bytes = sandbox.take_screenshot()
+    initial_screenshot_bytes = sandbox.screenshot()
     initial_image = Image.open(io.BytesIO(initial_screenshot_bytes))
     
     # Get cursor position and perform right click
@@ -26,7 +26,7 @@ def test_right_click(sandbox: Sandbox):
     time.sleep(5)  # Wait for UI to respond
     
     # Capture and process the second screenshot
-    post_click_screenshot_bytes = sandbox.take_screenshot()
+    post_click_screenshot_bytes = sandbox.screenshot()
     post_click_image = Image.open(io.BytesIO(post_click_screenshot_bytes))
     
     # Crop both images around the cursor position
@@ -37,7 +37,7 @@ def test_right_click(sandbox: Sandbox):
     assert not images_are_equal(cropped_image_1, cropped_image_2), "The image around the cursor did not change after right-click."
 
 def test_screenshot(sandbox: Sandbox):
-    image = sandbox.take_screenshot()
+    image = sandbox.screenshot()
     assert image, "Screenshot was not taken successfully"
     
     # Check if the image is a valid image format
diff --git a/readme-assets/screenshot.png b/readme-assets/screenshot.png
index 1125cdb..0ed3617 100644
Binary files a/readme-assets/screenshot.png and b/readme-assets/screenshot.png differ
diff --git a/template/e2b.Dockerfile b/template/e2b.Dockerfile
index 0343e77..316d21c 100644
--- a/template/e2b.Dockerfile
+++ b/template/e2b.Dockerfile
@@ -4,49 +4,47 @@ ENV DEBIAN_FRONTEND=noninteractive
 ENV DEBIAN_PRIORITY=high
 
 RUN yes | unminimize
-RUN apt-get --reinstall install -y python3-jwt python3-oauthlib python3-lazr.restfulclient \
+RUN apt-get update && apt-get --reinstall install -y python3-jwt python3-oauthlib python3-lazr.restfulclient \
     python3-launchpadlib python3-apport xserver-xorg apport xorg
 
 RUN apt-get update && apt-get install -y \
-  python3-xlib \
-  x11-xserver-utils \
-  xfce4 \
-  xfce4-goodies \
-  xvfb \
-  xubuntu-icon-theme \
-  scrot \
-  python3-pip \
-  python3-tk \
-  python3-dev \
-  x11-utils \
-  gnumeric \
-  python-is-python3 \
-  build-essential \
-  util-linux \
-  locales \
-  xauth \
-  gnome-screenshot \
-  xserver-xorg \
-  ffmpeg \
-  vim \
-  xorg
+    python3-xlib \
+    x11-xserver-utils \
+    xfce4 \
+    xfce4-goodies \
+    xvfb \
+    xubuntu-icon-theme \
+    scrot \
+    python3-pip \
+    python3-tk \
+    python3-dev \
+    x11-utils \
+    gnumeric \
+    python-is-python3 \
+    build-essential \
+    util-linux \
+    locales \
+    xauth \
+    gnome-screenshot \
+    xserver-xorg \
+    ffmpeg \
+    vim \
+    xorg
 
 RUN pip3 install mux_python requests
 
 # Install vscode
 RUN apt update -y \
-  && apt install -y software-properties-common apt-transport-https wget \
-  && wget -qO- https://packages.microsoft.com/keys/microsoft.asc | apt-key add - \
-  && add-apt-repository -y "deb [arch=amd64] https://packages.microsoft.com/repos/vscode stable main" \
-  && apt update -y \
-  && apt install -y code
+    && apt install -y software-properties-common apt-transport-https wget \
+    && wget -qO- https://packages.microsoft.com/keys/microsoft.asc | apt-key add - \
+    && add-apt-repository -y "deb [arch=amd64] https://packages.microsoft.com/repos/vscode stable main" \
+    && apt update -y \
+    && apt install -y code
 
 ENV PIP_DEFAULT_TIMEOUT=100 \
-  PIP_DISABLE_PIP_VERSION_CHECK=1 \
-  PIP_NO_CACHE_DIR=1 \
-  DEBIAN_FRONTEND=noninteractive
-
-RUN echo "export DISPLAY=:99" >> /etc/environment
+    PIP_DISABLE_PIP_VERSION_CHECK=1 \
+    PIP_NO_CACHE_DIR=1 \
+    DEBIAN_FRONTEND=noninteractive
 
 COPY ./requirements.txt requirements.txt
 RUN pip3 install --no-cache-dir -r requirements.txt
@@ -55,54 +53,66 @@ COPY ./45-allow-colord.pkla /etc/polkit-1/localauthority/50-local.d/45-allow-col
 
 COPY ./Xauthority /home/user/.Xauthority
 
-COPY ./start-up.sh /
-RUN chmod +x /start-up.sh
-
 RUN apt-get update && \
-  apt-get -y upgrade && \
-  apt-get -y install \
-  build-essential \
-  # UI Requirements
-  xvfb \
-  xterm \
-  xdotool \
-  scrot \
-  imagemagick \
-  sudo \
-  mutter \
-  x11vnc \
-  # Python/pyenv reqs
-  build-essential \
-  libssl-dev  \
-  zlib1g-dev \
-  libbz2-dev \
-  libreadline-dev \
-  libsqlite3-dev \
-  curl \
-  git \
-  libncursesw5-dev \
-  xz-utils \
-  tk-dev \
-  libxml2-dev \
-  libxmlsec1-dev \
-  libffi-dev \
-  liblzma-dev \
-  # Network tools
-  net-tools \
-  netcat \
-  # PPA req
-  software-properties-common && \
-  # Userland apps
-  sudo add-apt-repository ppa:mozillateam/ppa && \
-  sudo apt-get install -y --no-install-recommends \
-  libreoffice \
-  firefox-esr \
-  x11-apps \
-  xpdf \
-  gedit \
-  xpaint \
-  tint2 \
-  galculator \
-  pcmanfm \
-  unzip && \
-  apt-get clean
\ No newline at end of file
+    apt-get -y upgrade && \
+    apt-get -y install \
+    build-essential \
+    # UI Requirements
+    xvfb \
+    xterm \
+    xdotool \
+    scrot \
+    imagemagick \
+    sudo \
+    mutter \
+    x11vnc \
+    # Python/pyenv reqs
+    build-essential \
+    libssl-dev  \
+    zlib1g-dev \
+    libbz2-dev \
+    libreadline-dev \
+    libsqlite3-dev \
+    curl \
+    git \
+    libncursesw5-dev \
+    xz-utils \
+    tk-dev \
+    libxml2-dev \
+    libxmlsec1-dev \
+    libffi-dev \
+    liblzma-dev \
+    # Network tools
+    net-tools \
+    netcat \
+    # PPA req
+    software-properties-common && \
+    # Userland apps
+    sudo add-apt-repository ppa:mozillateam/ppa && \
+    sudo apt-get install -y --no-install-recommends \
+    libreoffice \
+    firefox-esr \
+    x11-apps \
+    xpdf \
+    gedit \
+    xpaint \
+    tint2 \
+    galculator \
+    pcmanfm \
+    unzip && \
+    apt-get clean
+
+# Install numpy which is used by websockify: https://github.com/novnc/websockify/issues/337
+RUN pip install numpy
+
+# Install noVNC and websockify
+#
+# Invalidate cache so we always pull the latest noVNC and websockify
+# otherwise, Docker might not execute the `RUN` command if it's cached from the previous build
+ARG CACHEBUST=1
+RUN git clone --branch e2b-desktop https://github.com/e2b-dev/noVNC.git /opt/noVNC && \
+    git clone --branch v0.12.0 https://github.com/novnc/websockify /opt/noVNC/utils/websockify && \
+    ln -s /opt/noVNC/vnc.html /opt/noVNC/index.html
+
+# Copy E2B desktop wallpaper
+COPY ./wallpaper.png /usr/share/backgrounds/xfce/wallpaper.png
\ No newline at end of file
diff --git a/template/e2b.toml b/template/e2b.toml
index 168da37..8384c6c 100644
--- a/template/e2b.toml
+++ b/template/e2b.toml
@@ -10,10 +10,9 @@
 # import { Sandbox } from 'e2b'
 # const sandbox = await Sandbox.create('desktop')
 
-template_id = "k0wmnzir0zuzye6dndlw"
+team_id = "460355b3-4f64-48f9-9a16-4442817f79f5"
+memory_mb = 4_096
+cpu_count = 4
 dockerfile = "e2b.Dockerfile"
 template_name = "desktop"
-start_cmd = "/start-up.sh"
-cpu_count = 4
-memory_mb = 4_096
-team_id = "460355b3-4f64-48f9-9a16-4442817f79f5"
+template_id = "k0wmnzir0zuzye6dndlw"
diff --git a/template/start-up.sh b/template/start-up.sh
deleted file mode 100644
index 9493721..0000000
--- a/template/start-up.sh
+++ /dev/null
@@ -1,8 +0,0 @@
-#!/bin/bash
-
-echo "export DISPLAY=:99" >> /home/user/.bashrc
-source /home/user/.bashrc
-
-Xvfb $DISPLAY -ac -screen 0 1024x768x24 &
-/usr/bin/xfce4-session
-# startxfce4
\ No newline at end of file
diff --git a/template/wallpaper.png b/template/wallpaper.png
new file mode 100644
index 0000000..668a79a
Binary files /dev/null and b/template/wallpaper.png differ