From 27508ea6e5646f8ac36e5d5aaf55e171eaf2fe2f Mon Sep 17 00:00:00 2001 From: Nathan Flurry Date: Sat, 27 Jun 2026 18:04:39 -0700 Subject: [PATCH] feat(website): migrate docs to de-Starlighted @rivet-dev/docs-theme - Replace Starlight with the shared @rivet-dev/docs-theme; plain glob content loader; secure-exec identity (logo/nav/footer/landing/sidebar) - docs.config sitemap with FA icons; embeds; topNav on marketing only; SDKs icon; tab strip hidden (single tab); JetBrains Mono code font; Full Example + Copy buttons - Typesense docs search (secureexec-docs collection) - website/Dockerfile: git-clone + build the theme at a pinned sha, generate FA icons (FONTAWESOME_PACKAGE_TOKEN build arg, set on Railway), copy examples, rewrite theme deps to the clone - Clean theme deps (file:vendor/theme, no machine path) Co-Authored-By: Claude Opus 4.8 (1M context) --- .dockerignore | 8 + .gitignore | 1 + .../docs/feat-module-loading/src/index.mts | 4 + examples/docs/uc-code-mode/src/index.mts | 6 + pnpm-lock.yaml | 4187 +++++++++++++++-- website/.astro/collections/docs.schema.json | 624 +-- website/.astro/content-modules.mjs | 16 +- website/.astro/data-store.json | 2 +- website/.astro/settings.json | 2 +- website/.gitignore | 1 + website/Dockerfile | 32 +- website/astro.config.mjs | 108 +- website/docs.config.mjs | 186 +- website/package.json | 10 +- website/public/docs/docs.md | 6 + website/public/docs/docs/architecture.md | 14 + website/public/docs/docs/benchmarks.md | 123 + .../docs/comparison/cloudflare-workers.md | 101 + .../docs/docs/comparison/isolated-vm.md | 87 + .../public/docs/docs/comparison/quickjs.md | 52 + .../public/docs/docs/comparison/sandbox.md | 86 + website/public/docs/docs/crash-course.md | 109 + website/public/docs/docs/features/bindings.md | 175 + .../docs/docs/features/child-processes.md | 97 + .../docs/docs/features/executing-code.md | 63 + .../public/docs/docs/features/filesystem.md | 15 + .../docs/docs/features/module-loading.md | 67 + .../public/docs/docs/features/networking.md | 14 + .../docs/docs/features/output-capture.md | 92 + .../public/docs/docs/features/permissions.md | 15 + .../docs/docs/features/resident-runner.md | 45 + .../docs/docs/features/resource-limits.md | 255 + .../docs/docs/features/runtime-platform.md | 199 + .../public/docs/docs/features/typescript.md | 81 + .../public/docs/docs/nodejs-compatibility.md | 135 + website/public/docs/docs/quickstart.md | 71 + website/public/docs/docs/sdks/rust.md | 22 + website/public/docs/docs/sdks/typescript.md | 27 + website/public/docs/docs/security-model.md | 14 + .../docs/docs/use-cases/ai-agent-code-exec.md | 44 + .../public/docs/docs/use-cases/code-mode.md | 61 + .../public/docs/docs/use-cases/dev-servers.md | 95 + .../docs/docs/use-cases/plugin-systems.md | 63 + .../JetBrainsMono-Variable-latin.woff2 | Bin 0 -> 40480 bytes .../manrope/Manrope-Variable-latin.woff2 | Bin 0 -> 24576 bytes website/src/components/Navigation.tsx | 6 +- website/src/content.config.ts | 17 +- .../src/content/docs/docs/architecture.mdx | 9 +- website/src/content/docs/docs/benchmarks.mdx | 3 +- .../docs/comparison/cloudflare-workers.mdx | 29 +- .../docs/docs/comparison/isolated-vm.mdx | 19 +- .../content/docs/docs/comparison/quickjs.mdx | 27 +- .../content/docs/docs/comparison/sandbox.mdx | 5 +- .../src/content/docs/docs/crash-course.mdx | 55 +- .../docs/docs/features/child-processes.mdx | 36 +- .../docs/docs/features/executing-code.mdx | 23 +- .../content/docs/docs/features/filesystem.mdx | 9 +- .../docs/docs/features/module-loading.mdx | 86 +- .../content/docs/docs/features/networking.mdx | 9 +- .../docs/docs/features/output-capture.mdx | 22 +- .../docs/docs/features/permissions.mdx | 9 +- .../docs/docs/features/resident-runner.mdx | 9 +- .../docs/docs/features/resource-limits.mdx | 11 +- .../docs/docs/features/runtime-platform.mdx | 89 +- .../content/docs/docs/features/typescript.mdx | 67 +- website/src/content/docs/docs/index.mdx | 6 +- .../docs/docs/nodejs-compatibility.mdx | 5 +- website/src/content/docs/docs/quickstart.mdx | 127 +- website/src/content/docs/docs/sdks/rust.mdx | 9 +- .../src/content/docs/docs/sdks/typescript.mdx | 9 +- .../src/content/docs/docs/security-model.mdx | 9 +- .../docs/use-cases/ai-agent-code-exec.mdx | 51 +- .../content/docs/docs/use-cases/code-mode.mdx | 103 +- .../docs/docs/use-cases/dev-servers.mdx | 6 +- .../docs/docs/use-cases/plugin-systems.mdx | 75 +- website/src/data/docs-landings.ts | 32 + website/src/generated/routes.json | 120 + website/src/lib/starlight-shim.jsx | 58 + website/src/pages/[...slug].astro | 101 + website/src/styles/global.css | 8 + website/tailwind.config.mjs | 14 +- 81 files changed, 6782 insertions(+), 1906 deletions(-) create mode 100644 website/public/docs/docs.md create mode 100644 website/public/docs/docs/architecture.md create mode 100644 website/public/docs/docs/benchmarks.md create mode 100644 website/public/docs/docs/comparison/cloudflare-workers.md create mode 100644 website/public/docs/docs/comparison/isolated-vm.md create mode 100644 website/public/docs/docs/comparison/quickjs.md create mode 100644 website/public/docs/docs/comparison/sandbox.md create mode 100644 website/public/docs/docs/crash-course.md create mode 100644 website/public/docs/docs/features/bindings.md create mode 100644 website/public/docs/docs/features/child-processes.md create mode 100644 website/public/docs/docs/features/executing-code.md create mode 100644 website/public/docs/docs/features/filesystem.md create mode 100644 website/public/docs/docs/features/module-loading.md create mode 100644 website/public/docs/docs/features/networking.md create mode 100644 website/public/docs/docs/features/output-capture.md create mode 100644 website/public/docs/docs/features/permissions.md create mode 100644 website/public/docs/docs/features/resident-runner.md create mode 100644 website/public/docs/docs/features/resource-limits.md create mode 100644 website/public/docs/docs/features/runtime-platform.md create mode 100644 website/public/docs/docs/features/typescript.md create mode 100644 website/public/docs/docs/nodejs-compatibility.md create mode 100644 website/public/docs/docs/quickstart.md create mode 100644 website/public/docs/docs/sdks/rust.md create mode 100644 website/public/docs/docs/sdks/typescript.md create mode 100644 website/public/docs/docs/security-model.md create mode 100644 website/public/docs/docs/use-cases/ai-agent-code-exec.md create mode 100644 website/public/docs/docs/use-cases/code-mode.md create mode 100644 website/public/docs/docs/use-cases/dev-servers.md create mode 100644 website/public/docs/docs/use-cases/plugin-systems.md create mode 100644 website/public/fonts/jetbrains-mono/JetBrainsMono-Variable-latin.woff2 create mode 100644 website/public/fonts/manrope/Manrope-Variable-latin.woff2 create mode 100644 website/src/data/docs-landings.ts create mode 100644 website/src/generated/routes.json create mode 100644 website/src/lib/starlight-shim.jsx create mode 100644 website/src/pages/[...slug].astro diff --git a/.dockerignore b/.dockerignore index f478a1156..66d239ca3 100644 --- a/.dockerignore +++ b/.dockerignore @@ -20,3 +20,11 @@ packages/core/* website/node_modules website/dist website/.astro + +# The docs embeds read example source from /examples (the embed +# root is the parent of the website). Include the example source only. +!examples +examples/**/node_modules +examples/**/dist +examples/**/.astro +examples/**/target diff --git a/.gitignore b/.gitignore index c1707fc68..3e2f3c700 100644 --- a/.gitignore +++ b/.gitignore @@ -83,3 +83,4 @@ packages/core/commands/ # Transient repro scratch files and Vite/Vitest config timestamp artifacts .tmp-* *.timestamp-*.mjs +website/vendor/ diff --git a/examples/docs/feat-module-loading/src/index.mts b/examples/docs/feat-module-loading/src/index.mts index de1bd2331..527b6293a 100644 --- a/examples/docs/feat-module-loading/src/index.mts +++ b/examples/docs/feat-module-loading/src/index.mts @@ -1,6 +1,7 @@ import { fileURLToPath } from "node:url"; import { NodeRuntime } from "secure-exec"; +// docs:start loading-modules // Boot a fully virtualized VM. Module resolution runs entirely inside the // kernel - `import` and `require` resolve against the guest's virtual // filesystem, never the host's. @@ -38,9 +39,11 @@ try { } finally { await rt.dispose(); } +// docs:end loading-modules // --- Loading real npm packages from the host ------------------------------ +// docs:start npm-packages // Point `nodeModules` at a host `node_modules` directory and the whole tree is // projected into the VM in one call. Any package inside resolves the way Node // would over a real filesystem, symlinks and all. Here we mount this repo's @@ -83,3 +86,4 @@ try { } finally { await mounted.dispose(); } +// docs:end npm-packages diff --git a/examples/docs/uc-code-mode/src/index.mts b/examples/docs/uc-code-mode/src/index.mts index 705d5965e..e41bcd02d 100644 --- a/examples/docs/uc-code-mode/src/index.mts +++ b/examples/docs/uc-code-mode/src/index.mts @@ -1,3 +1,4 @@ +// docs:start bindings import { NodeRuntime } from "secure-exec"; function readStringField(input: unknown, field: string): string { @@ -58,7 +59,9 @@ const rt = await NodeRuntime.create({ }, }, }); +// docs:end bindings +// docs:start generated-code // Imagine this string was written by the LLM. It chains three host binding calls // with real control flow (Promise.all, arithmetic, branching) in one execution, // then hands a single structured result back to the host. callBinding resolves @@ -81,7 +84,9 @@ globalThis.__return({ warmer: sf.temp_f > tokyo.temp_f ? "San Francisco" : "Tokyo", }); `; +// docs:end generated-code +// docs:start run interface CodeModeResult { san_francisco: { temp_f: number }; tokyo: { temp_f: number }; @@ -102,3 +107,4 @@ try { } finally { await rt.dispose(); } +// docs:end run diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 0197da33d..7dcc166b5 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -1030,15 +1030,18 @@ importers: '@astrojs/sitemap': specifier: ^3.2.0 version: 3.7.3 - '@astrojs/starlight': - specifier: ^0.36.0 - version: 0.36.3(astro@5.18.2(@types/node@24.13.2)(jiti@1.21.7)(rollup@4.60.1)(tsx@4.21.0)(typescript@5.9.3)(yaml@2.9.0)) '@astrojs/tailwind': specifier: ^6.0.0 version: 6.0.2(astro@5.18.2(@types/node@24.13.2)(jiti@1.21.7)(rollup@4.60.1)(tsx@4.21.0)(typescript@5.9.3)(yaml@2.9.0))(tailwindcss@3.4.19(tsx@4.21.0)(yaml@2.9.0)) '@rivet-dev/docs-theme': - specifier: github:rivet-dev/docs-theme#v0.1.0 - version: https://codeload.github.com/rivet-dev/docs-theme/tar.gz/ed588a45112cfe70c9abe6e8f52e8fe47a1d6162(@astrojs/starlight@0.36.3(astro@5.18.2(@types/node@24.13.2)(jiti@1.21.7)(rollup@4.60.1)(tsx@4.21.0)(typescript@5.9.3)(yaml@2.9.0)))(astro@5.18.2(@types/node@24.13.2)(jiti@1.21.7)(rollup@4.60.1)(tsx@4.21.0)(typescript@5.9.3)(yaml@2.9.0)) + specifier: file:vendor/theme + version: file:website/vendor/theme(@babel/core@7.29.7)(@babel/runtime@7.29.7)(@babel/template@7.29.7)(@codemirror/language@6.12.4)(@codemirror/search@6.7.1)(@codemirror/theme-one-dark@6.1.3)(@types/node@24.13.2)(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(astro@5.18.2(@types/node@24.13.2)(jiti@1.21.7)(rollup@4.60.1)(tsx@4.21.0)(typescript@5.9.3)(yaml@2.9.0))(codemirror@6.0.2)(jiti@1.21.7)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)(tsx@4.21.0)(use-sync-external-store@1.6.0(react@19.2.7))(yaml@2.9.0) + '@rivet-gg/components': + specifier: file:vendor/theme/vendor/components + version: file:website/vendor/theme/vendor/components(@babel/core@7.29.7)(@babel/runtime@7.29.7)(@babel/template@7.29.7)(@codemirror/language@6.12.4)(@codemirror/search@6.7.1)(@codemirror/theme-one-dark@6.1.3)(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(codemirror@6.0.2)(lodash@4.18.1)(posthog-js@1.395.0)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)(tailwindcss@3.4.19(tsx@4.21.0)(yaml@2.9.0)) + '@rivet-gg/icons': + specifier: file:vendor/theme/vendor/icons + version: file:website/vendor/theme/vendor/icons(@fortawesome/fontawesome-svg-core@6.7.2)(@fortawesome/free-brands-svg-icons@6.7.2)(@fortawesome/free-solid-svg-icons@6.7.2)(@fortawesome/react-fontawesome@0.2.6(@fortawesome/fontawesome-svg-core@6.7.2)(react@19.2.7))(react-dom@19.2.7(react@19.2.7))(react@19.2.7) astro: specifier: ^5.18.2 version: 5.18.2(@types/node@24.13.2)(jiti@1.21.7)(rollup@4.60.1)(tsx@4.21.0)(typescript@5.9.3)(yaml@2.9.0) @@ -1102,6 +1105,9 @@ packages: resolution: {integrity: sha512-UrcABB+4bUrFABwbluTIBErXwvbsU/V7TZWfmbgJfbkwiBuziS9gxdODUyuiecfdGQ85jglMW6juS3+z5TsKLw==} engines: {node: '>=10'} + '@antfu/install-pkg@1.1.0': + resolution: {integrity: sha512-MGQsmw10ZyI+EJo45CdSER4zEb+p31LpDAFp2Z3gkSd1yqVZGi0Ebx++YTEMonJy4oChEMLsxZ64j8FH6sSqtQ==} + '@anthropic-ai/claude-agent-sdk@0.2.87': resolution: {integrity: sha512-WWmgBPxPhBOvNT0ujI8vPTI2lK+w5YEkEZ/y1mH0EDkK/0kBnxVJNhCtG5vnueiAViwLoUOFn66pbkDiivijdA==} engines: {node: '>=18.0.0'} @@ -1157,11 +1163,6 @@ packages: '@astrojs/sitemap@3.7.3': resolution: {integrity: sha512-f8euLVsyeAmAkSm/1M2Kb8sL8byQmfgbvBNaHFItCheTj/IpiJYSEWVcqDHZ/yEHxiS7+w87mQkzwZaPHmk5GA==} - '@astrojs/starlight@0.36.3': - resolution: {integrity: sha512-5cm4QVQHUP6ZE52O43TtUpsTvLKdZa9XEs4l3suzuY7Ymsbz4ojtoL9NhistbMqM+/qk6fm6SmxbOL6hQ/LfNA==} - peerDependencies: - astro: ^5.5.0 - '@astrojs/tailwind@6.0.2': resolution: {integrity: sha512-j3mhLNeugZq6A8dMNXVarUa8K6X9AW+QHU9u3lKNrPLMHhOQ0S7VeWhHwEeJFpEK1BTKEUY1U78VQv2gN6hNGg==} peerDependencies: @@ -1430,13 +1431,45 @@ packages: '@borewit/text-codec@0.2.2': resolution: {integrity: sha512-DDaRehssg1aNrH4+2hnj1B7vnUGEjU6OIlyRdkMd0aUdIUvKXrJfXsy8LVtXAy7DRvYVluWbMspsRhz2lcW0mQ==} + '@braintree/sanitize-url@7.1.2': + resolution: {integrity: sha512-jigsZK+sMF/cuiB7sERuo9V7N9jx+dhmHHnQyDSVdpZwVutaBu7WvNYqMDLSgFgfB30n452TP3vjDAvFC973mA==} + '@capsizecss/unpack@4.0.1': resolution: {integrity: sha512-CuNiSqg7+e1cO/GjffyMOm5Tt2jUF9CWHHnvQ/UkqvtkGfHdgwEC0wpmq7fkN3gxwpRnrAN0WzO3vREKmNolMQ==} engines: {node: '>=18'} - '@ctrl/tinycolor@4.2.0': - resolution: {integrity: sha512-kzyuwOAQnXJNLS9PSyrk0CWk35nWJW/zl/6KvnTBMFK65gm7U1/Z5BqjxeapjZCIhQcM/DsrEmcbRwDyXyXK4A==} - engines: {node: '>=14'} + '@chevrotain/types@11.1.2': + resolution: {integrity: sha512-U+HFai5+zmJCkK86QsaJtoITlboZHBqrVketcO2ROv865xfCMSFpELQoz1GkX5GzME8pTa+3kbKrZHQtI0gdbw==} + + '@codemirror/autocomplete@6.20.3': + resolution: {integrity: sha512-tlosUqb+3BbxCxZdu4tKeRghPFC+QM7q4X5YhKV2eCmPG+1r2F3f4AaSz5sCrFqUtX4Jh20VFTKecl16MgiV9g==} + + '@codemirror/commands@6.10.4': + resolution: {integrity: sha512-Ryk9y9T0FFVF0cUGhAknveAyUOl/A1qReTFi+qPKtOh2Z9F4AUBz3XOrYD4ZEgZirdugVzHvd/2/Wcwy5OliTg==} + + '@codemirror/lang-javascript@6.2.5': + resolution: {integrity: sha512-zD4e5mS+50htS7F+TYjBPsiIFGanfVqg4HyUz6WNFikgOPf2BgKlx+TQedI1w6n/IqRBVBbBWmGFdLB/7uxO4A==} + + '@codemirror/lang-json@6.0.2': + resolution: {integrity: sha512-x2OtO+AvwEHrEwR0FyyPtfDUiloG3rnVTSZV1W8UteaLL8/MajQd8DpvUb2YVzC+/T18aSDv0H9mu+xw0EStoQ==} + + '@codemirror/language@6.12.4': + resolution: {integrity: sha512-1q4PaT+o6PbgpkJt4Q8Fv5XJxTy4FUZ4MWETtyiDw3J0Pyr9E2vqcKL+k9wcvjNTIsauxvE7OfmWj3FRPHQ76A==} + + '@codemirror/lint@6.9.7': + resolution: {integrity: sha512-28/+iWLYxKxsvGYhSYL7zaCZqLz5+FFFDq9tVsvGv9kv8RY4fFAchJ5WX9M3YrrRlTIsECjsXPqeNgnSmNP2dg==} + + '@codemirror/search@6.7.1': + resolution: {integrity: sha512-uMe5UO6PamJtSHrXhhHOzSX3ReWtiJrva6GnPMwSOrZtiExb5X5eExhr2OUZQVvdxPsKpY3Ro2mFbQadpPWmHA==} + + '@codemirror/state@6.7.0': + resolution: {integrity: sha512-Zbl9NyscLMZkfXPQnNAIIAFftidrA1UbcJEIMp24C0Bukc2I5T8wJS0wsXYsnDOqCFJUeJ1BITGNs5CqPDSmSg==} + + '@codemirror/theme-one-dark@6.1.3': + resolution: {integrity: sha512-NzBdIvEJmx6fjeremiGp3t/okrLPYT0d9orIc7AFun8oZcRk58aejkqhv6spnz4MLAevrKNPMQYXEWMg4s+sKA==} + + '@codemirror/view@6.43.4': + resolution: {integrity: sha512-YImu23iyKfncJzT7sRy+rEqEhSc8RhOHqDxwy4WzXRKJwYm6iwf/9OJk5ctCAdZ6yi2ZqaGEvmf55fSVqMDrgg==} '@emnapi/runtime@1.11.1': resolution: {integrity: sha512-vgj7R3y3Wgx24IQaGPA/R6YFXLHVMOZ0uVEyIQPaWs+rd1AzfEMXlAC22FYwO1XkKR6NPsq7mUandH8oIRdZFw==} @@ -1891,17 +1924,76 @@ packages: cpu: [x64] os: [win32] - '@expressive-code/core@0.41.7': - resolution: {integrity: sha512-ck92uZYZ9Wba2zxkiZLsZGi9N54pMSAVdrI9uW3Oo9AtLglD5RmrdTwbYPCT2S/jC36JGB2i+pnQtBm/Ib2+dg==} + '@floating-ui/core@1.7.5': + resolution: {integrity: sha512-1Ih4WTWyw0+lKyFMcBHGbb5U5FtuHJuujoyyr5zTaWS5EYMeT6Jb2AuDeftsCsEuchO+mM2ij5+q9crhydzLhQ==} + + '@floating-ui/dom@1.7.6': + resolution: {integrity: sha512-9gZSAI5XM36880PPMm//9dfiEngYoC6Am2izES1FF406YFsjvyBMmeJ2g4SAju3xWwtuynNRFL2s9hgxpLI5SQ==} + + '@floating-ui/react-dom@2.1.8': + resolution: {integrity: sha512-cC52bHwM/n/CxS87FH0yWdngEZrjdtLW/qVruo68qg+prK7ZQ4YGdut2GyDVpoGeAYe/h899rVeOVm6Oi40k2A==} + peerDependencies: + react: '>=16.8.0' + react-dom: '>=16.8.0' + + '@floating-ui/react@0.26.28': + resolution: {integrity: sha512-yORQuuAtVpiRjpMhdc0wJj06b9JFjrYF4qp96j++v2NBpbi6SEGF7donUJ3TMieerQ6qVkAv1tgr7L4r5roTqw==} + peerDependencies: + react: '>=16.8.0' + react-dom: '>=16.8.0' + + '@floating-ui/utils@0.2.11': + resolution: {integrity: sha512-RiB/yIh78pcIxl6lLMG0CgBXAZ2Y0eVHqMPYugu+9U0AeT6YBeiJpf7lbdJNIugFP5SIjwNRgo4DhR1Qxi26Gg==} + + '@fortawesome/fontawesome-common-types@6.7.2': + resolution: {integrity: sha512-Zs+YeHUC5fkt7Mg1l6XTniei3k4bwG/yo3iFUtZWd/pMx9g3fdvkSK9E0FOC+++phXOka78uJcYb8JaFkW52Xg==} + engines: {node: '>=6'} + + '@fortawesome/fontawesome-common-types@7.3.0': + resolution: {integrity: sha512-X/vND0Y1l9fVJ9O79UgtZnXSpz4aNF3bXlDxiJAEAm6kgeSftp9wjjBPgqzazJV8YlmxfRoeXNfSCJ48sf/Hhw==} + engines: {node: '>=6'} + + '@fortawesome/fontawesome-free@6.7.2': + resolution: {integrity: sha512-JUOtgFW6k9u4Y+xeIaEiLr3+cjoUPiAuLXoyKOJSia6Duzb7pq+A76P9ZdPDoAoxHdHzq6gE9/jKBGXlZT8FbA==} + engines: {node: '>=6'} + + '@fortawesome/fontawesome-svg-core@6.7.2': + resolution: {integrity: sha512-yxtOBWDrdi5DD5o1pmVdq3WMCvnobT0LU6R8RyyVXPvFRd2o79/0NCuQoCjNTeZz9EzA9xS3JxNWfv54RIHFEA==} + engines: {node: '>=6'} + + '@fortawesome/fontawesome-svg-core@7.3.0': + resolution: {integrity: sha512-MFbTNLDWkLJwbozDvHOZ7hwyDjQcBMBattlcOQ6ZmV5YD9bBrqdl1rNtmVjQ/lzqveXXX3sMz2Ew6fAgXoxmkw==} + engines: {node: '>=6'} + + '@fortawesome/free-brands-svg-icons@6.7.2': + resolution: {integrity: sha512-zu0evbcRTgjKfrr77/2XX+bU+kuGfjm0LbajJHVIgBWNIDzrhpRxiCPNT8DW5AdmSsq7Mcf9D1bH0aSeSUSM+Q==} + engines: {node: '>=6'} + + '@fortawesome/free-brands-svg-icons@7.3.0': + resolution: {integrity: sha512-W6C9ZbPWpwcUycq6U90lVbvWTrEnr01Td2x5jlO8fOtvww4kqDBMSmZqXQCc6FIIJD4kTH6G1MBRExAaSXz3yg==} + engines: {node: '>=6'} + + '@fortawesome/free-solid-svg-icons@6.7.2': + resolution: {integrity: sha512-GsBrnOzU8uj0LECDfD5zomZJIjrPhIlWU82AHwa2s40FKH+kcxQaBvBo3Z4TxyZHIyX8XTDxsyA33/Vx9eFuQA==} + engines: {node: '>=6'} - '@expressive-code/plugin-frames@0.41.7': - resolution: {integrity: sha512-diKtxjQw/979cTglRFaMCY/sR6hWF0kSMg8jsKLXaZBSfGS0I/Hoe7Qds3vVEgeoW+GHHQzMcwvgx/MOIXhrTA==} + '@fortawesome/free-solid-svg-icons@7.3.0': + resolution: {integrity: sha512-YxI/CuwWeI3nPIoYU//vkDS+3ige/67DPZ6XwMATpYEFESzO9L8zfJOKllGRgIlpT/uebrZCcvAzp3peD7GmTw==} + engines: {node: '>=6'} - '@expressive-code/plugin-shiki@0.41.7': - resolution: {integrity: sha512-DL605bLrUOgqTdZ0Ot5MlTaWzppRkzzqzeGEu7ODnHF39IkEBbFdsC7pbl3LbUQ1DFtnfx6rD54k/cdofbW6KQ==} + '@fortawesome/react-fontawesome@0.2.6': + resolution: {integrity: sha512-mtBFIi1UsYQo7rYonYFkjgYKGoL8T+fEH6NGUpvuqtY3ytMsAoDaPo5rk25KuMtKDipY4bGYM/CkmCHA1N3FUg==} + deprecated: v0.2.x is no longer supported. Unless you are still using FontAwesome 5, please update to v3.1.1 or greater. + peerDependencies: + '@fortawesome/fontawesome-svg-core': ~1 || ~6 || ~7 + react: ^16.3 || ^17.0.0 || ^18.0.0 || ^19.0.0 - '@expressive-code/plugin-text-markers@0.41.7': - resolution: {integrity: sha512-Ewpwuc5t6eFdZmWlFyeuy3e1PTQC0jFvw2Q+2bpcWXbOZhPLsT7+h8lsSIJxb5mS7wZko7cKyQ2RLYDyK6Fpmw==} + '@fortawesome/react-fontawesome@3.3.1': + resolution: {integrity: sha512-wGnAPhfzivDwBWYmEG8MSrEXPruoiMMo48NnsRkj1NZkoaawgOijPNAiSHKMYEoCsqTBSgLTzL6EqTTWGaUR4w==} + engines: {node: '>=20'} + peerDependencies: + '@fortawesome/fontawesome-svg-core': ~6 || ~7 + react: ^18.0.0 || ^19.0.0 '@gerrit0/mini-shiki@3.23.0': resolution: {integrity: sha512-bEMORlG0cqdjVyCEuU0cDQbORWX+kYCeo0kV1lbxF5bt4r7SID2l9bqsxJEM0zndaxpOUT7riCyIVEuqq/Ynxg==} @@ -1929,12 +2021,30 @@ packages: engines: {node: '>=6'} hasBin: true + '@headlessui/react@2.2.10': + resolution: {integrity: sha512-5pVLNK9wlpxTUTy9GpgbX/SdcRh+HBnPktjM2wbiLTH4p+2EPHBO1aoSryUCuKUIItdDWO9ITlhUL8UnUN/oIA==} + engines: {node: '>=10'} + peerDependencies: + react: ^18 || ^19 || ^19.0.0-rc + react-dom: ^18 || ^19 || ^19.0.0-rc + '@hono/node-server@1.19.14': resolution: {integrity: sha512-GwtvgtXxnWsucXvbQXkRgqksiH2Qed37H9xHZocE5sA3N8O8O8/8FA3uclQXxXVzc9XBZuEOMK7+r02FmSpHtw==} engines: {node: '>=18.14.1'} peerDependencies: hono: ^4 + '@hookform/resolvers@3.10.0': + resolution: {integrity: sha512-79Dv+3mDF7i+2ajj7SkypSKHhl1cbln1OGavqrsF7p6mbUv11xpqpacPsGDCTRvCSjEEIez2ef1NveSVL3b0Ag==} + peerDependencies: + react-hook-form: ^7.0.0 + + '@iconify/types@2.0.0': + resolution: {integrity: sha512-+wluvCrRhXrhyOmRDJ3q8mux9JkKy5SJ/v8ol2tu4FVjyYvtEzkc/3pK15ET6RKg4b4w4BmTk1+gsCUhf21Ykg==} + + '@iconify/utils@3.1.3': + resolution: {integrity: sha512-LPKOXPn/zV+zis1oOfGWogaXVpqUybF3ZS6SCZIsz8vg0ivVp9+fVqyYB7xq0aiST/VhUQYGO1qo6uoYSiEJqw==} + '@img/colour@1.1.0': resolution: {integrity: sha512-Td76q7j57o/tLVdgS746cYARfSyxk8iEfRxewL9h4OMzYhbW4TAcppl0mT4eyqXddh6L/jwoM75mo7ixa/pCeQ==} engines: {node: '>=18'} @@ -2177,6 +2287,15 @@ packages: cpu: [x64] os: [win32] + '@internationalized/date@3.12.2': + resolution: {integrity: sha512-FY1Y+H64NDs+HAF6omlnWxm3mEpfgaCSWtL5l551ZZfImA+kGjPFgrnJrGjH6lfmLL0g8Z/mBu1R3kufeCp6Jw==} + + '@internationalized/number@3.6.7': + resolution: {integrity: sha512-3ji1fcrT+FPAK86UqEhB/psHixYo6niWPJtt7+qRaYFynt/BaJG8GhAPimtWUpEiVSTq8ZM8L5psMxGquiB/Vg==} + + '@internationalized/string@3.2.9': + resolution: {integrity: sha512-kzP/M/mbQxODlmOt4bIQZ2SBVUWUSqMLXooXixnX7noche8WHaQcA+nwFN1K2KCF/cp+LDUhcJsCicwkvhD1pg==} + '@isaacs/cliui@8.0.2': resolution: {integrity: sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==} engines: {node: '>=12'} @@ -2200,6 +2319,24 @@ packages: '@js-sdsl/ordered-map@4.4.2': resolution: {integrity: sha512-iUKgm52T8HOE/makSxjqoWhe95ZJA1/G1sYsGev2JDKUSS14KAgg1LHb+Ba+IPow0xflbnSkOsZcO08C7w1gYw==} + '@lezer/common@1.5.2': + resolution: {integrity: sha512-sxQE460fPZyU3sdc8lafxiPwJHBzZRy/udNFynGQky1SePYBdhkBl1kOagA9uT3pxR8K09bOrmTUqA9wb/PjSQ==} + + '@lezer/highlight@1.2.3': + resolution: {integrity: sha512-qXdH7UqTvGfdVBINrgKhDsVTJTxactNNxLk7+UMwZhU13lMHaOBlJe9Vqp907ya56Y3+ed2tlqzys7jDkTmW0g==} + + '@lezer/javascript@1.5.4': + resolution: {integrity: sha512-vvYx3MhWqeZtGPwDStM2dwgljd5smolYD2lR2UyFcHfxbBQebqx8yjmFmxtJ/E6nN6u1D9srOiVWm3Rb4tmcUA==} + + '@lezer/json@1.0.3': + resolution: {integrity: sha512-BP9KzdF9Y35PDpv04r0VeSTKDeox5vVr3efE7eBbx3r4s3oNLfunchejZhjArmeieBH+nVOpgIiBJpEAv8ilqQ==} + + '@lezer/lr@1.4.10': + resolution: {integrity: sha512-rnCpTIBafOx4mRp43xOxDJbFipJm/c0cia/V5TiGlhmMa+wsSdoGmUN3w5Bqrks/09Q/D4tNAmWaT8p6NRi77A==} + + '@marijn/find-cluster-break@1.0.3': + resolution: {integrity: sha512-FY+MKLBoTsLNJF/eLWaOsXGdz6uh3Iu1axjPf6TUq92IYumcTcXWHoS747JARLkcdlJ/Waiaxc5wQfFO8jC6NA==} + '@mariozechner/clipboard-darwin-arm64@0.3.9': resolution: {integrity: sha512-BfgV7vCEWZwJwZJw03r6bP5+tf0iI/ANuQYCxi9RNn7FrWB3yzGuMKCrNLRl6V761vXRdL8+OqZ0wd4TqlsNOQ==} engines: {node: '>= 10'} @@ -2292,6 +2429,9 @@ packages: '@mdx-js/mdx@3.1.1': resolution: {integrity: sha512-f6ZO2ifpwAQIpzGWaBQT2TXxPv6z3RBzQKpVftEWN78Vl/YweF1uwussDx8ECAXVtr3Rs89fKyG9YlzUs9DyGQ==} + '@mermaid-js/parser@1.2.0': + resolution: {integrity: sha512-oYPyv8A4As1yH5Bx+04iQEQxXuIQDe0GKCNSRgao6z8AM9jixXIfP0vsppRLvGf+nKIOb9/LdpWA4YuJiVvESA==} + '@mistralai/mistralai@1.14.1': resolution: {integrity: sha512-IiLmmZFCCTReQgPAT33r7KQ1nYo5JPdvGkrkZqA8qQ2qB1GHgs5LoP5K2ICyrjnpw2n8oSxMM/VP+liiKcGNlQ==} @@ -2380,44 +2520,6 @@ packages: cpu: [x64] os: [win32] - '@pagefind/darwin-arm64@1.5.2': - resolution: {integrity: sha512-MXpI+7HsAdPkvJ0gk9xj9g541BCqBZOBbdwj9g6lB5LCj6kSV6nqDSjzcAJwvOsfu0fjwvC8hQU+ecfhp+MpiQ==} - cpu: [arm64] - os: [darwin] - - '@pagefind/darwin-x64@1.5.2': - resolution: {integrity: sha512-IojxFWMEJe0RQ7PQ3KXQsPIImNsbpPYpoZ+QUDrL8fAl/O27IX+LVLs74/UzEZy5uA2LD8Nz1AiwKr72vrkZQw==} - cpu: [x64] - os: [darwin] - - '@pagefind/default-ui@1.5.2': - resolution: {integrity: sha512-pm1LMnQg8N2B3n2TnjKlhaFihpz6zTiA4HiGQ6/slKO/+8K9CAU5kcjdSSPgpuk1PMuuN4hxLipUIifnrkl3Sg==} - - '@pagefind/freebsd-x64@1.5.2': - resolution: {integrity: sha512-7EVzo9+0w+2cbe671BtMj10UlNo83I+HrLVLfRxO731svHRJKUfJ/mo05gU14pe9PCfpKNQT8FS3Xc/oDN6pOA==} - cpu: [x64] - os: [freebsd] - - '@pagefind/linux-arm64@1.5.2': - resolution: {integrity: sha512-Ovt9+K35sqzn8H3ZMXGwls4TD/wMJuvRtShHIsmUQREmaxjrDEX7gHckRCrwYJ4XE1H1p6HkLz3wukrAnsfXQw==} - cpu: [arm64] - os: [linux] - - '@pagefind/linux-x64@1.5.2': - resolution: {integrity: sha512-V+tFqHKXhQKq/WqPBD67AFy7scn1/aZID00ws4fSDd+1daSi5UHR9VVlRrOUYKxn3VuFQYRD7lYXdZK1WED1YA==} - cpu: [x64] - os: [linux] - - '@pagefind/windows-arm64@1.5.2': - resolution: {integrity: sha512-hN9Nh90fNW61nNRCW9ZyQrAj/mD0eRvmJ8NlTUzkbuW8kIzGJUi3cxjFkEcMZ5h/8FsKWD/VcouZl4yo1F7B6g==} - cpu: [arm64] - os: [win32] - - '@pagefind/windows-x64@1.5.2': - resolution: {integrity: sha512-Fa2Iyw7kaDRzGMfNYNUXNW2zbL5FQVDgSOcbDHdzBrDEdpqOqg8TcZ68F22ol6NJ9IGzvUdmeyZypLW5dyhqsg==} - cpu: [x64] - os: [win32] - '@pkgjs/parseargs@0.11.0': resolution: {integrity: sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==} engines: {node: '>=14'} @@ -2427,6 +2529,12 @@ packages: engines: {node: '>=18'} hasBin: true + '@posthog/core@1.38.0': + resolution: {integrity: sha512-QLrJh0hMVpEJXHNyiJR9YhvIO5tzLDedw4UHdvB+ub4fXHMtHCA8H44qgl11HWR3ajpjxtJ8hs3HyOGVF3Zc1w==} + + '@posthog/types@1.391.1': + resolution: {integrity: sha512-ASwd7Nf4pViqdYRYaNRyPYRVKWa1CcHUAUWR0XeQJLGdNnsWACBwe0sSieb/cHnKsRXjRwO/23KIY83lm/Ccpw==} + '@protobufjs/aspromise@1.1.2': resolution: {integrity: sha512-j+gKExEuLmKwvz3OgROXtrJ2UG2x8Ch2YZUxahh+s1F2HZ+wAceUNLkvy6zKCPVRkU++ZWQrdxsUeQXmcg4uoQ==} @@ -2457,111 +2565,698 @@ packages: '@protobufjs/utf8@1.1.0': resolution: {integrity: sha512-Vvn3zZrhQZkkBE8LSuW3em98c0FwgO4nxzv6OdSxPKJIEKY2bGbHn+mhGIPerzI4twdxaP8/0+06HBpwf345Lw==} - '@rivet-dev/docs-theme@https://codeload.github.com/rivet-dev/docs-theme/tar.gz/ed588a45112cfe70c9abe6e8f52e8fe47a1d6162': - resolution: {tarball: https://codeload.github.com/rivet-dev/docs-theme/tar.gz/ed588a45112cfe70c9abe6e8f52e8fe47a1d6162} - version: 0.1.0 - peerDependencies: - '@astrojs/starlight': '>=0.36.0' - astro: '>=5.0.0' + '@radix-ui/number@1.1.2': + resolution: {integrity: sha512-ceTwaxc4I5IOi97DgCotl3pqiyRGvffcc0oOsE2dQYaJOFIDsDt4VWG6xEbg1QePv9QWausCEIppud/tJ1wNig==} - '@rivetkit/bare-ts@0.6.2': - resolution: {integrity: sha512-3qndQUQXLdwafMEqfhz24hUtDPcsf1Bu3q52Kb8MqeH8JUh3h6R4HYW3ZJXiQsLcyYyFM68PuIwlLRlg1xDEpg==} - engines: {node: ^14.18.0 || >=16.0.0} + '@radix-ui/primitive@1.1.4': + resolution: {integrity: sha512-7AdCK9PQyiljKoBDbN8OuctCbd/esdwZPQ8RtOE3SsyQtUpiPb+ND75q0jEhC1m1ecBI0MFNeLJvwIh9iKHRcQ==} - '@rolldown/pluginutils@1.0.0-beta.27': - resolution: {integrity: sha512-+d0F4MKMCbeVUJwG96uQ4SgAznZNSq93I3V+9NHA4OpvqG8mRCpGdKmK8l/dl02h2CCDHwW2FqilnTyDcAnqjA==} + '@radix-ui/react-accordion@1.2.14': + resolution: {integrity: sha512-iE8YB9nmTBH8zd73ofBISZ8JCzgMoMkATJr7qDwa6u5F1+7mTM81V6fa71jgZ65rpjVpecDf1vSnwIFP9Ly1zw==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true - '@rollup/pluginutils@5.4.0': - resolution: {integrity: sha512-MfPp06CjRLfXQ3wY0R8vJDYBy/MvVcc9OulEfR0B8Iv9ko+GCNaRZ+EpJYFl27LhKsZK0o420sYCRHCjfCgeUg==} - engines: {node: '>=14.0.0'} + '@radix-ui/react-arrow@1.1.10': + resolution: {integrity: sha512-j2VTDz1vgCsmuG0k5lBfOcM8n5JPFqZBcMryasFjHYMhwxYL5SRUV5lMSUpRdNtw3D/Sv8pzJtrlAgkssYSsQQ==} peerDependencies: - rollup: ^1.20.0||^2.0.0||^3.0.0||^4.0.0 + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc peerDependenciesMeta: - rollup: + '@types/react': + optional: true + '@types/react-dom': optional: true - '@rollup/rollup-android-arm-eabi@4.60.1': - resolution: {integrity: sha512-d6FinEBLdIiK+1uACUttJKfgZREXrF0Qc2SmLII7W2AD8FfiZ9Wjd+rD/iRuf5s5dWrr1GgwXCvPqOuDquOowA==} - cpu: [arm] - os: [android] + '@radix-ui/react-avatar@1.2.0': + resolution: {integrity: sha512-am/CwltXtmtdtP+5FbYblYDnMa/zuKcMJP1i3/SJMDXXfj2mG+BTqLH2wucqeyyiQMursUtg/5cK+Nh2pCaSOA==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true - '@rollup/rollup-android-arm64@4.60.1': - resolution: {integrity: sha512-YjG/EwIDvvYI1YvYbHvDz/BYHtkY4ygUIXHnTdLhG+hKIQFBiosfWiACWortsKPKU/+dUwQQCKQM3qrDe8c9BA==} - cpu: [arm64] - os: [android] + '@radix-ui/react-checkbox@1.3.5': + resolution: {integrity: sha512-pREzrmNnVwGvYaBoM64huTRK7B3lrTRuwj8A9nwhPiEtMb+yudiWh6zWAqEtP0Dzd5+iBa1Ki7V1pCxV8ExMdA==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true - '@rollup/rollup-darwin-arm64@4.60.1': - resolution: {integrity: sha512-mjCpF7GmkRtSJwon+Rq1N8+pI+8l7w5g9Z3vWj4T7abguC4Czwi3Yu/pFaLvA3TTeMVjnu3ctigusqWUfjZzvw==} - cpu: [arm64] - os: [darwin] + '@radix-ui/react-collapsible@1.1.14': + resolution: {integrity: sha512-9bT+FvifX1FK2Mj6UEsTdyu0cN3JaA3KdfhaBao+ONrYFy/pyOy3TU1TNw7iOk1o+0hOEq67RojlUUmoFGwxyA==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true - '@rollup/rollup-darwin-x64@4.60.1': - resolution: {integrity: sha512-haZ7hJ1JT4e9hqkoT9R/19XW2QKqjfJVv+i5AGg57S+nLk9lQnJ1F/eZloRO3o9Scy9CM3wQ9l+dkXtcBgN5Ew==} - cpu: [x64] - os: [darwin] + '@radix-ui/react-collection@1.1.10': + resolution: {integrity: sha512-IVVz4EvBcKjrzKgof714qDnz/SzQAkLA2Emh5edlHbgcE6fNd3Un6CJLlaYcnm8N4JmAtzQgse4dOKxcD2yc9g==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true - '@rollup/rollup-freebsd-arm64@4.60.1': - resolution: {integrity: sha512-czw90wpQq3ZsAVBlinZjAYTKduOjTywlG7fEeWKUA7oCmpA8xdTkxZZlwNJKWqILlq0wehoZcJYfBvOyhPTQ6w==} - cpu: [arm64] - os: [freebsd] + '@radix-ui/react-compose-refs@1.1.3': + resolution: {integrity: sha512-rYOP8OMnuuPMQF1uhPVlGNcCDlkokKqGFE3JcxFViIkAXP7EvFWUliJAstrapypaBLJNHbZL6jGhbVDGTwmVhA==} + peerDependencies: + '@types/react': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true - '@rollup/rollup-freebsd-x64@4.60.1': - resolution: {integrity: sha512-KVB2rqsxTHuBtfOeySEyzEOB7ltlB/ux38iu2rBQzkjbwRVlkhAGIEDiiYnO2kFOkJp+Z7pUXKyrRRFuFUKt+g==} - cpu: [x64] - os: [freebsd] + '@radix-ui/react-context-menu@2.3.1': + resolution: {integrity: sha512-XbrxS68W5dyiE4fAb96yvJwSVU5x66B20A99sD5Mk3xSWK/LqeOnx6TZnim1KieMjXS/CTFq8reOAjWxas2G8Q==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true - '@rollup/rollup-linux-arm-gnueabihf@4.60.1': - resolution: {integrity: sha512-L+34Qqil+v5uC0zEubW7uByo78WOCIrBvci69E7sFASRl0X7b/MB6Cqd1lky/CtcSVTydWa2WZwFuWexjS5o6g==} - cpu: [arm] - os: [linux] + '@radix-ui/react-context@1.1.4': + resolution: {integrity: sha512-QwH4PO5urrbO+FaGd5Aglg+YJgWTyyuZ3g/6mKvsqraLkglDdckw9JafgL5McL5VEJ6EPNduPaT3ZE9BttDAqg==} + peerDependencies: + '@types/react': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true - '@rollup/rollup-linux-arm-musleabihf@4.60.1': - resolution: {integrity: sha512-n83O8rt4v34hgFzlkb1ycniJh7IR5RCIqt6mz1VRJD6pmhRi0CXdmfnLu9dIUS6buzh60IvACM842Ffb3xd6Gg==} - cpu: [arm] - os: [linux] + '@radix-ui/react-dialog@1.1.17': + resolution: {integrity: sha512-TDTYmpdq8dI2+Xgvgj9AJ8Ghqq+Eph/TRVEdaFQPDItIY+6QSkU7MJMeevw1568Yw/2Ijz8BTphPSP2XejKphw==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true - '@rollup/rollup-linux-arm64-gnu@4.60.1': - resolution: {integrity: sha512-Nql7sTeAzhTAja3QXeAI48+/+GjBJ+QmAH13snn0AJSNL50JsDqotyudHyMbO2RbJkskbMbFJfIJKWA6R1LCJQ==} - cpu: [arm64] - os: [linux] + '@radix-ui/react-direction@1.1.2': + resolution: {integrity: sha512-C3vFhbyi4SW3PmbAi6Awpu4OzJtd0MxGurvSsYtr7p7nM8RNB3VAF3CUmnp2j50knpkrRcB7+ycVXzgLgF6yNA==} + peerDependencies: + '@types/react': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true - '@rollup/rollup-linux-arm64-musl@4.60.1': - resolution: {integrity: sha512-+pUymDhd0ys9GcKZPPWlFiZ67sTWV5UU6zOJat02M1+PiuSGDziyRuI/pPue3hoUwm2uGfxdL+trT6Z9rxnlMA==} - cpu: [arm64] - os: [linux] + '@radix-ui/react-dismissable-layer@1.1.13': + resolution: {integrity: sha512-2v+zNAWWe0ySxgC0D0yeXMPQ23xZVgXZTerTz+JKlmdRj6gfTqmCcR29jb6d290DezXPGgruHWDX/vYUebtErg==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true - '@rollup/rollup-linux-loong64-gnu@4.60.1': - resolution: {integrity: sha512-VSvgvQeIcsEvY4bKDHEDWcpW4Yw7BtlKG1GUT4FzBUlEKQK0rWHYBqQt6Fm2taXS+1bXvJT6kICu5ZwqKCnvlQ==} - cpu: [loong64] - os: [linux] + '@radix-ui/react-dropdown-menu@2.1.18': + resolution: {integrity: sha512-PZGV82gFk0WltDRI//SsG28ZIjlo9ANTmoNYg0jLNzXXiDsAy5PkOOYQaVD1pPxY6t7gxffb1QMD6qaUvsBZdw==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true - '@rollup/rollup-linux-loong64-musl@4.60.1': - resolution: {integrity: sha512-4LqhUomJqwe641gsPp6xLfhqWMbQV04KtPp7/dIp0nzPxAkNY1AbwL5W0MQpcalLYk07vaW9Kp1PBhdpZYYcEw==} - cpu: [loong64] - os: [linux] + '@radix-ui/react-focus-guards@1.1.4': + resolution: {integrity: sha512-cot/aB/mOm0IYVYTTmQcEEK1M48lZWi8FlYe5nDPQQ8NYZUlXEFgncJ9p2Kzer3RKSrY7cTTpEMLZKNo9QoP5Q==} + peerDependencies: + '@types/react': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true - '@rollup/rollup-linux-ppc64-gnu@4.60.1': - resolution: {integrity: sha512-tLQQ9aPvkBxOc/EUT6j3pyeMD6Hb8QF2BTBnCQWP/uu1lhc9AIrIjKnLYMEroIz/JvtGYgI9dF3AxHZNaEH0rw==} - cpu: [ppc64] - os: [linux] + '@radix-ui/react-focus-scope@1.1.10': + resolution: {integrity: sha512-Fas/lXQqhVvqwAb64s5RFeHiHYElZ6SUQbZaNd6EkfhP/Al7wTIQ9WIR4QVX475tlu5yFCEdDcJH6/UwsZjMWw==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true - '@rollup/rollup-linux-ppc64-musl@4.60.1': - resolution: {integrity: sha512-RMxFhJwc9fSXP6PqmAz4cbv3kAyvD1etJFjTx4ONqFP9DkTkXsAMU4v3Vyc5BgzC+anz7nS/9tp4obsKfqkDHg==} - cpu: [ppc64] - os: [linux] + '@radix-ui/react-id@1.1.2': + resolution: {integrity: sha512-orBC88futVpqCmhX1p4cvquNHsELQ+w+vBJnuj3ftETI5bJb0bZn3Tqu3SWN2IOcPycTnMGnhwoermvISt72sA==} + peerDependencies: + '@types/react': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true - '@rollup/rollup-linux-riscv64-gnu@4.60.1': - resolution: {integrity: sha512-QKgFl+Yc1eEk6MmOBfRHYF6lTxiiiV3/z/BRrbSiW2I7AFTXoBFvdMEyglohPj//2mZS4hDOqeB0H1ACh3sBbg==} - cpu: [riscv64] - os: [linux] + '@radix-ui/react-label@2.1.10': + resolution: {integrity: sha512-ib0zvq2ZsAqKm5tRnqGJn3vOxSgIts5ToxsXT0q1S/GfLD1Zj7UOEnkw8u2w6sRmn47djpQWuSU1DCL1R29/yw==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true - '@rollup/rollup-linux-riscv64-musl@4.60.1': - resolution: {integrity: sha512-RAjXjP/8c6ZtzatZcA1RaQr6O1TRhzC+adn8YZDnChliZHviqIjmvFwHcxi4JKPSDAt6Uhf/7vqcBzQJy0PDJg==} - cpu: [riscv64] - os: [linux] + '@radix-ui/react-menu@2.1.18': + resolution: {integrity: sha512-lj8Rxjtn6zJq1oSbE/uDtAwCbB9BnxgHD+8MwJMuTh6u1dPamYhW9iuELr/Z8d0D/UysFblYYHeBPwi7T4k0YQ==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true - '@rollup/rollup-linux-s390x-gnu@4.60.1': - resolution: {integrity: sha512-wcuocpaOlaL1COBYiA89O6yfjlp3RwKDeTIA0hM7OpmhR1Bjo9j31G1uQVpDlTvwxGn2nQs65fBFL5UFd76FcQ==} + '@radix-ui/react-popover@1.1.17': + resolution: {integrity: sha512-/YSAOdJ7YJvdn7bn5sdSx2egW+SKY+u7O5RyAVs94Ymrg2fg5QTSFPMRkzvhGyFuE4/qsmPBdrwYoZMZh/4f+g==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + + '@radix-ui/react-popper@1.3.1': + resolution: {integrity: sha512-bhnq/0DEPTi2lsOD3J5rTL65qUKHbKbhqHsmN9TMiclSXpipi651ooUKPPp6G5lF/WiHBdn1s0Wuqsn+myVAvw==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + + '@radix-ui/react-portal@1.1.12': + resolution: {integrity: sha512-m309havGzsjLHHaIX50G5PlvRs3xkgPCsGk/5PTvYm8D5q33yG0J7w/712PTOhid7NTaFETtnSXjngHQavvhVw==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + + '@radix-ui/react-presence@1.1.6': + resolution: {integrity: sha512-zdTk4PlUO0E18HnZ3wYbW0KkJJxWCdiNYp6g6X1PtONFhxVkg01vliTJAmwIszU6mHiyBOoW9P0rAugl5/hULQ==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + + '@radix-ui/react-primitive@2.1.6': + resolution: {integrity: sha512-wetd0QI77DbvrPpTAvH1SqOxsYF2wZe5TNxqwOd5Ty4XDpV3dpV0s8K/1MGMJBeY5o7lg8ub5VIt1Ub+yVen6g==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + + '@radix-ui/react-progress@1.1.10': + resolution: {integrity: sha512-JYzEg60lk79PwKM27WZyKd7PW8O4OM5jOaFfRPfOyeXmMw7tLJh5kSj+CEjVTehszuwml/AdCzPGMXBTGf4BBw==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + + '@radix-ui/react-radio-group@1.4.1': + resolution: {integrity: sha512-/SSxZdKEo2Eo29FFRKd06EfFDYp8HryKg0WYg7QLXaydPzl52YfSvCH2a3QDBRdtcuwACroJT8UVjQVgOJ7P9A==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + + '@radix-ui/react-roving-focus@1.1.13': + resolution: {integrity: sha512-9gkwneI0guf8JDmrFxPjJF6Ozzgioyw+/lonYNCwefS9ZHA05er0BVHiXr+LbWGHxUfczvMY6G1oiZZi1VzjRw==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + + '@radix-ui/react-scroll-area@1.2.12': + resolution: {integrity: sha512-xuafVzQiTCLsyEjakowTdG3OgTXsmO7IdCiO77otIa+z44xoLNs9Do5eg7POFumIOCjtG6djfm6RKUKpUa/csA==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + + '@radix-ui/react-select@2.3.1': + resolution: {integrity: sha512-w6eDvY78LE9ZUiNnXCA1QVK8RYN7k9galFv09kjVydJqBAgHd7Y9A6h0UJ/6DCZNGZMZrB2ohcSW1Bo9d8+wWA==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + + '@radix-ui/react-separator@1.1.10': + resolution: {integrity: sha512-Y6K6jLQCVfCnTL2MEtGxDLffkhNfEfHsEg3Wa8JU+IWdn3EWbLXd3OuOfQRN7p/W/cUce1WyTk3QeuAoDBzN9g==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + + '@radix-ui/react-slider@1.4.1': + resolution: {integrity: sha512-r91WSpQucNGFKAIxT8FT0H0zyjd5tJlqObLp7LOMV4z49KoDCwjy01w3vDOU4e1wxhF9IgjYco7SB6byOW7Buw==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + + '@radix-ui/react-slot@1.3.0': + resolution: {integrity: sha512-MojKku4U/miO8Av4Dkb+ctMAQx7JmY96LmtDQlAarCRtd7rN52QCSzBF+XAvr5S6coSVj9HEPBgHAHKEJVk/WA==} + peerDependencies: + '@types/react': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + + '@radix-ui/react-switch@1.3.1': + resolution: {integrity: sha512-55bQtCnOB0BohomSHi6qvQXpJEEqUGDm6hRrM0Bph5OXwhSegqkd8IqgBAQkM1IlgUlWZIxpxRcpOEfRIgimyw==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + + '@radix-ui/react-tabs@1.1.15': + resolution: {integrity: sha512-kxc9gI6/HfcU4nfMMVS3AmQK414kbU1IE6UCJmMmxjhO3cRPXOyYnmvyKD+ODt7q56nRq9l7Wovi6uaGwKgMlg==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + + '@radix-ui/react-toggle-group@1.1.13': + resolution: {integrity: sha512-Xb9PLtlvU66F36LiKba6dFswu6V2mDkgidO4fNSbQHQwmZ9ObxMIO17MN/LJ4aWJecVuSVLAHPZjyeMzJrgeiA==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + + '@radix-ui/react-toggle@1.1.12': + resolution: {integrity: sha512-AsAVsYNZIlRBsci7BhE+QyQeKd1h6TffJYt+lF0QQkd5OpQ3klfIByPsCb4G0h/Fq6PJwh1FYNluzBFYzhk4+w==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + + '@radix-ui/react-tooltip@1.2.10': + resolution: {integrity: sha512-NlNe8D0dWEpVfXFli90IO6X07Josx/b1iu98tDnx9Xv0HT4wLIL+m2VOheMHhK7qbp2HoTBqALEFzGyZs/levw==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + + '@radix-ui/react-use-callback-ref@1.1.2': + resolution: {integrity: sha512-xCso9j1/u8sEgP1RNHjFrXJLApL8LiqOkI1R4ywuN00rxWdYg4oQXuwKLS3i0j5NWLromUD27/4nlxj2UFVvIw==} + peerDependencies: + '@types/react': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + + '@radix-ui/react-use-controllable-state@1.2.3': + resolution: {integrity: sha512-PLzC90MS+ReootmjC597dvopoelpZ8Q61HJkDXZSExitIq7PL55vHNnesAHwguHK0aPfBnpdNzQtv1uliaqQrA==} + peerDependencies: + '@types/react': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + + '@radix-ui/react-use-effect-event@0.0.3': + resolution: {integrity: sha512-6c8ZqvPTWILEKnyVkP53EGRCcpnJiKTC21sS/6R1GF5xKyHJJWQEPfkqlcgUkdRQivd6tb23abUwe4ngWmY0JA==} + peerDependencies: + '@types/react': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + + '@radix-ui/react-use-escape-keydown@1.1.2': + resolution: {integrity: sha512-2uVLvLjgO7NZCWw01/FdqRwmA42J0BcjPMUCA+koFEOAb+zjqIP7SiFz/7zWPrKnVmSqr76Omq2ALyCuX4dhLw==} + peerDependencies: + '@types/react': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + + '@radix-ui/react-use-is-hydrated@0.1.1': + resolution: {integrity: sha512-qwOiz4Tjo8CNnrOLAYUMXeZwDzXgXpvK4TKQPmWLECM9XoWvA6+0Z2/7Ag3A4ivjS4ovbLJPbskkxioFyBhr8A==} + peerDependencies: + '@types/react': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + + '@radix-ui/react-use-layout-effect@1.1.2': + resolution: {integrity: sha512-jrBWOxZITuGcnjRCM2t2U5ZPkCLxD+Ym6DjfssS5haTj2iiak/DOb64JeN6OdLfLgptb6/e2kKR+ZuTrGoZTPA==} + peerDependencies: + '@types/react': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + + '@radix-ui/react-use-previous@1.1.2': + resolution: {integrity: sha512-IGBQPtRFdhN6MQ8dbegVmBq1LVZluya3F1jWY+puIcQC3MHctRwTDSBWCkL/3ZcnMJLTMJ++Z+ktmvg0F89iCw==} + peerDependencies: + '@types/react': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + + '@radix-ui/react-use-rect@1.1.2': + resolution: {integrity: sha512-d8a+bBY/FxikNPlgJJoaBHZX+zKVbWHYJGTLnLvveQgFSTntkGdEKv3JDtHrMS0DNYpllz2nRsTLGLKYttbpmw==} + peerDependencies: + '@types/react': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + + '@radix-ui/react-use-size@1.1.2': + resolution: {integrity: sha512-giWQp+4mxjBPt4KZ0MmyuykFNWfbDxKt4x+fPkRYmgRFJSbCZFzUglvMb/Kjn38tm10YP4ufiQZDx3zna4LU6w==} + peerDependencies: + '@types/react': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + + '@radix-ui/react-visually-hidden@1.2.6': + resolution: {integrity: sha512-jCE0WljWifTI4niIMCll06kGpsJTAPiZVU9H4WR1N6qW7At9ystHbN7dDB+we2xH535roFHj7qKS+RGj0FMDWQ==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + + '@radix-ui/rect@1.1.2': + resolution: {integrity: sha512-xnXE7wG13PI+cxieVssYXlQJuYVRhH9NBoxt3KNwzghDIA69GMm7d4wXRouHIYjE+KvS6U/MsMO73NdS2MH9ZA==} + + '@react-aria/focus@3.22.1': + resolution: {integrity: sha512-CPxtkyrBi/HYY5P3lE/57sQ6qfa0lN8E55TOm89H0kNGv0lKt+/0zP7lWERzBjRr5IxBVrQX4gFEowBN52LPaA==} + peerDependencies: + react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1 + react-dom: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1 + + '@react-aria/interactions@3.28.1': + resolution: {integrity: sha512-Bqb+HrD5I5MHS2SKBhISYqo2SW8Y2dfzgF/Y1lIJq7xqLxheo9vzxPGEHhz+XzkgGfoqEJx8A6a3C7uiqS3HWA==} + peerDependencies: + react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1 + react-dom: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1 + + '@react-types/shared@3.36.0': + resolution: {integrity: sha512-DkP/H0C2YjjS7gZWKNqOmU8a16qHPjQNdzMwmTq9SzplM6Iw0kVMTZ0OIoe6FOgGqa+FwMsE2QbPjh/n3g/jXQ==} + peerDependencies: + react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1 + + '@rivet-dev/docs-theme@file:website/vendor/theme': + resolution: {directory: website/vendor/theme, type: directory} + hasBin: true + peerDependencies: + astro: '>=5.0.0' + react: '>=19.0.0' + react-dom: '>=19.0.0' + + '@rivet-gg/components@file:website/vendor/theme/vendor/components': + resolution: {directory: website/vendor/theme/vendor/components, type: directory} + peerDependencies: + lodash: ^4.0.0 + posthog-js: ^1.0.0 + react: ^19 + react-dom: ^19 + peerDependenciesMeta: + posthog-js: + optional: true + + '@rivet-gg/icons@file:website/vendor/theme/vendor/icons': + resolution: {directory: website/vendor/theme/vendor/icons, type: directory} + engines: {node: '>=18'} + peerDependencies: + '@fortawesome/fontawesome-svg-core': ^6.5.2 + '@fortawesome/free-brands-svg-icons': ^6.5.2 + '@fortawesome/free-solid-svg-icons': ^6.5.2 + '@fortawesome/react-fontawesome': ^0.2.2 + react: ^19 + react-dom: ^19 + + '@rivetkit/bare-ts@0.6.2': + resolution: {integrity: sha512-3qndQUQXLdwafMEqfhz24hUtDPcsf1Bu3q52Kb8MqeH8JUh3h6R4HYW3ZJXiQsLcyYyFM68PuIwlLRlg1xDEpg==} + engines: {node: ^14.18.0 || >=16.0.0} + + '@rolldown/pluginutils@1.0.0-beta.27': + resolution: {integrity: sha512-+d0F4MKMCbeVUJwG96uQ4SgAznZNSq93I3V+9NHA4OpvqG8mRCpGdKmK8l/dl02h2CCDHwW2FqilnTyDcAnqjA==} + + '@rollup/pluginutils@5.4.0': + resolution: {integrity: sha512-MfPp06CjRLfXQ3wY0R8vJDYBy/MvVcc9OulEfR0B8Iv9ko+GCNaRZ+EpJYFl27LhKsZK0o420sYCRHCjfCgeUg==} + engines: {node: '>=14.0.0'} + peerDependencies: + rollup: ^1.20.0||^2.0.0||^3.0.0||^4.0.0 + peerDependenciesMeta: + rollup: + optional: true + + '@rollup/rollup-android-arm-eabi@4.60.1': + resolution: {integrity: sha512-d6FinEBLdIiK+1uACUttJKfgZREXrF0Qc2SmLII7W2AD8FfiZ9Wjd+rD/iRuf5s5dWrr1GgwXCvPqOuDquOowA==} + cpu: [arm] + os: [android] + + '@rollup/rollup-android-arm64@4.60.1': + resolution: {integrity: sha512-YjG/EwIDvvYI1YvYbHvDz/BYHtkY4ygUIXHnTdLhG+hKIQFBiosfWiACWortsKPKU/+dUwQQCKQM3qrDe8c9BA==} + cpu: [arm64] + os: [android] + + '@rollup/rollup-darwin-arm64@4.60.1': + resolution: {integrity: sha512-mjCpF7GmkRtSJwon+Rq1N8+pI+8l7w5g9Z3vWj4T7abguC4Czwi3Yu/pFaLvA3TTeMVjnu3ctigusqWUfjZzvw==} + cpu: [arm64] + os: [darwin] + + '@rollup/rollup-darwin-x64@4.60.1': + resolution: {integrity: sha512-haZ7hJ1JT4e9hqkoT9R/19XW2QKqjfJVv+i5AGg57S+nLk9lQnJ1F/eZloRO3o9Scy9CM3wQ9l+dkXtcBgN5Ew==} + cpu: [x64] + os: [darwin] + + '@rollup/rollup-freebsd-arm64@4.60.1': + resolution: {integrity: sha512-czw90wpQq3ZsAVBlinZjAYTKduOjTywlG7fEeWKUA7oCmpA8xdTkxZZlwNJKWqILlq0wehoZcJYfBvOyhPTQ6w==} + cpu: [arm64] + os: [freebsd] + + '@rollup/rollup-freebsd-x64@4.60.1': + resolution: {integrity: sha512-KVB2rqsxTHuBtfOeySEyzEOB7ltlB/ux38iu2rBQzkjbwRVlkhAGIEDiiYnO2kFOkJp+Z7pUXKyrRRFuFUKt+g==} + cpu: [x64] + os: [freebsd] + + '@rollup/rollup-linux-arm-gnueabihf@4.60.1': + resolution: {integrity: sha512-L+34Qqil+v5uC0zEubW7uByo78WOCIrBvci69E7sFASRl0X7b/MB6Cqd1lky/CtcSVTydWa2WZwFuWexjS5o6g==} + cpu: [arm] + os: [linux] + + '@rollup/rollup-linux-arm-musleabihf@4.60.1': + resolution: {integrity: sha512-n83O8rt4v34hgFzlkb1ycniJh7IR5RCIqt6mz1VRJD6pmhRi0CXdmfnLu9dIUS6buzh60IvACM842Ffb3xd6Gg==} + cpu: [arm] + os: [linux] + + '@rollup/rollup-linux-arm64-gnu@4.60.1': + resolution: {integrity: sha512-Nql7sTeAzhTAja3QXeAI48+/+GjBJ+QmAH13snn0AJSNL50JsDqotyudHyMbO2RbJkskbMbFJfIJKWA6R1LCJQ==} + cpu: [arm64] + os: [linux] + + '@rollup/rollup-linux-arm64-musl@4.60.1': + resolution: {integrity: sha512-+pUymDhd0ys9GcKZPPWlFiZ67sTWV5UU6zOJat02M1+PiuSGDziyRuI/pPue3hoUwm2uGfxdL+trT6Z9rxnlMA==} + cpu: [arm64] + os: [linux] + + '@rollup/rollup-linux-loong64-gnu@4.60.1': + resolution: {integrity: sha512-VSvgvQeIcsEvY4bKDHEDWcpW4Yw7BtlKG1GUT4FzBUlEKQK0rWHYBqQt6Fm2taXS+1bXvJT6kICu5ZwqKCnvlQ==} + cpu: [loong64] + os: [linux] + + '@rollup/rollup-linux-loong64-musl@4.60.1': + resolution: {integrity: sha512-4LqhUomJqwe641gsPp6xLfhqWMbQV04KtPp7/dIp0nzPxAkNY1AbwL5W0MQpcalLYk07vaW9Kp1PBhdpZYYcEw==} + cpu: [loong64] + os: [linux] + + '@rollup/rollup-linux-ppc64-gnu@4.60.1': + resolution: {integrity: sha512-tLQQ9aPvkBxOc/EUT6j3pyeMD6Hb8QF2BTBnCQWP/uu1lhc9AIrIjKnLYMEroIz/JvtGYgI9dF3AxHZNaEH0rw==} + cpu: [ppc64] + os: [linux] + + '@rollup/rollup-linux-ppc64-musl@4.60.1': + resolution: {integrity: sha512-RMxFhJwc9fSXP6PqmAz4cbv3kAyvD1etJFjTx4ONqFP9DkTkXsAMU4v3Vyc5BgzC+anz7nS/9tp4obsKfqkDHg==} + cpu: [ppc64] + os: [linux] + + '@rollup/rollup-linux-riscv64-gnu@4.60.1': + resolution: {integrity: sha512-QKgFl+Yc1eEk6MmOBfRHYF6lTxiiiV3/z/BRrbSiW2I7AFTXoBFvdMEyglohPj//2mZS4hDOqeB0H1ACh3sBbg==} + cpu: [riscv64] + os: [linux] + + '@rollup/rollup-linux-riscv64-musl@4.60.1': + resolution: {integrity: sha512-RAjXjP/8c6ZtzatZcA1RaQr6O1TRhzC+adn8YZDnChliZHviqIjmvFwHcxi4JKPSDAt6Uhf/7vqcBzQJy0PDJg==} + cpu: [riscv64] + os: [linux] + + '@rollup/rollup-linux-s390x-gnu@4.60.1': + resolution: {integrity: sha512-wcuocpaOlaL1COBYiA89O6yfjlp3RwKDeTIA0hM7OpmhR1Bjo9j31G1uQVpDlTvwxGn2nQs65fBFL5UFd76FcQ==} cpu: [s390x] os: [linux] @@ -2637,6 +3332,36 @@ packages: resolution: {integrity: sha512-trO//ypJBSt5xkewuol9LOykvDgHwUXq8R+yQVS+0CmpN3lYUtewHkb+At9RVGRhDMmJZY2oasaXDnhfurQ33w==} hasBin: true + '@sentry-internal/browser-utils@8.55.2': + resolution: {integrity: sha512-GnKod+gL/Y+1FUM/RGV8q6le1CoyiGbT40MitEK7eVwWe+bfTRq1gN7ioupyHFMUg1RlQkDQ4/sENmio/uow5A==} + engines: {node: '>=14.18'} + + '@sentry-internal/feedback@8.55.2': + resolution: {integrity: sha512-XQy//NWbL0mLLM5w8wNDWMNpXz39VUyW2397dUrH8++kR63WhUVAvTOtL0o0GMVadSAzl1b08oHP9zSUNFQwcg==} + engines: {node: '>=14.18'} + + '@sentry-internal/replay-canvas@8.55.2': + resolution: {integrity: sha512-P/jGiuR7dRLG9IzD/463fLgiibyYceauav/9prRG0ZxJm1AtuO02OKball2Fs3bbzdzwHCTlcsUuL2ivDF4b5A==} + engines: {node: '>=14.18'} + + '@sentry-internal/replay@8.55.2': + resolution: {integrity: sha512-+W43Z697EVe/OgpGW07B773sa8xO1UbpnW0Cr+E+3FMDb6ZbXlaBUoagPTUkkQPdwBe35SDh6r8y2M3EOPGbxg==} + engines: {node: '>=14.18'} + + '@sentry/browser@8.55.2': + resolution: {integrity: sha512-xHuPIEKhx9zw5quWvv4YgZprnwoVMCfxIhmOIf6KJ9iizyUHeUDcKpLS59xERroqwX4RpvK+l/27AZu4zfZlzQ==} + engines: {node: '>=14.18'} + + '@sentry/core@8.55.2': + resolution: {integrity: sha512-YlEBwybUcOQ/KjMHDmof1vwweVnBtBxYlQp7DE3fOdtW4pqqdHWTnTntQs4VgYfxzjJYgtkd9LHlGtg8qy+JVQ==} + engines: {node: '>=14.18'} + + '@sentry/react@8.55.2': + resolution: {integrity: sha512-1TPfKZYkJal2Dyt2W0tf1roOZmu7sqr6/dTqjdsuu2WgGTilMEreK26YqB8ROOYdMjkVJpNCcIKXQHyMp2eCwA==} + engines: {node: '>=14.18'} + peerDependencies: + react: ^16.14.0 || 17.x || 18.x || 19.x + '@shikijs/core@3.23.0': resolution: {integrity: sha512-NSWQz0riNb67xthdm5br6lAkvpDJRTgB36fxlo37ZzM2yq0PQFFzbd8psqC2XMPgCzo1fW6cVi18+ArJ44wqgA==} @@ -2652,6 +3377,9 @@ packages: '@shikijs/themes@3.23.0': resolution: {integrity: sha512-5qySYa1ZgAT18HR/ypENL9cUSGOeI2x+4IvYJu4JgVJdizn6kG4ia5Q1jDEOi7gTbN4RbuYtmHh0W3eccOrjMA==} + '@shikijs/transformers@3.23.0': + resolution: {integrity: sha512-F9msZVxdF+krQNSdQ4V+Ja5QemeAoTQ2jxt7nJCwhDsdF1JWS3KxIQXA3lQbyKwS3J61oHRUSv4jYWv3CkaKTQ==} + '@shikijs/types@3.23.0': resolution: {integrity: sha512-3JZ5HXOZfYjsYSk0yPwBrkupyYSLpAE26Qc0HLghhZNGTZg/SKxXIIgoxOpmmeQP0RRSDJTk1/vPfw9tbw+jSQ==} @@ -2664,6 +3392,14 @@ packages: '@sinclair/typebox@0.34.49': resolution: {integrity: sha512-brySQQs7Jtn0joV8Xh9ZV/hZb9Ozb0pmazDIASBkYKCjXrXU3mpcFahmK/z4YDhGkQvP9mWJbVyahdtU5wQA+A==} + '@sindresorhus/slugify@3.0.0': + resolution: {integrity: sha512-SCrKh1zS96q+CuH5GumHcyQEVPsM4Ve8oE0E6tw7AAhGq50K8ojbTUOQnX/j9Mhcv/AXiIsbCfquovyGOo5fGw==} + engines: {node: '>=20'} + + '@sindresorhus/transliterate@2.3.1': + resolution: {integrity: sha512-gVaaGtKYMYAMmI8buULVH3A2TXVJ98QiwGwI7ddrWGuGidGC2uRt4FHs22+8iROJ0QTzju9CuMjlVsrvpqsdhA==} + engines: {node: '>=20'} + '@smithy/core@3.26.0': resolution: {integrity: sha512-mLUktFAn+Pa2agl1J7VgtYNFWCX8/b4GMJSK1hCu4YCvtBfM6F8Os3EP4ry+DFFlXOf3wyvlgXhuUdFoy52D3g==} engines: {node: '>=18.0.0'} @@ -2700,6 +3436,39 @@ packages: resolution: {integrity: sha512-R8Rdn8Hy72KKcebgLiv8jQcQkXoLMOGGv5uI1/k0l+snqkOzQ1R0ChUBCxWMlBsFMekWjq0wRudIweFs7sKT5A==} engines: {node: '>=14.0.0'} + '@swc/helpers@0.5.23': + resolution: {integrity: sha512-5lSsMOTXURePglDfvuAQUqkGek9Hg2kksOYay2m0+XR++b2NWYL/4sWyuvVBIs8oKnJaxkdi9whaL/sqN13afw==} + + '@tailwindcss/container-queries@0.1.1': + resolution: {integrity: sha512-p18dswChx6WnTSaJCSGx6lTmrGzNNvm2FtXmiO6AuA1V4U5REyoqwmT6kgAsIMdjo07QdAfYXHJ4hnMtfHzWgA==} + peerDependencies: + tailwindcss: '>=3.2.0' + + '@tailwindcss/typography@0.5.20': + resolution: {integrity: sha512-hwbzQuNUfcPvbegQFatVPl/MY/tcM9KLl963hQ5laJKPh81TEZ1+dNG9PirGvcaDBkp+BCshExAyKVPW91dozw==} + peerDependencies: + tailwindcss: '>=3.0.0 || >=4.0.0 || insiders' + + '@tanstack/react-table@8.21.3': + resolution: {integrity: sha512-5nNMTSETP4ykGegmVkhjcS8tTLW6Vl4axfEGQN3v0zdHYbK4UfoqfPChclTrJ4EoK9QynqAu9oUf8VEmrpZ5Ww==} + engines: {node: '>=12'} + peerDependencies: + react: '>=16.8' + react-dom: '>=16.8' + + '@tanstack/react-virtual@3.14.4': + resolution: {integrity: sha512-dZzAQP2uCDAd+9sAehqmx/DcU+B91Q4Gb0aDSM7t9bJvWDyGF9sapFNW5r1gNLsHs4wTb6ScZENJeYaHxJLiOw==} + peerDependencies: + react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 + react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 + + '@tanstack/table-core@8.21.3': + resolution: {integrity: sha512-ldZXEhOBb8Is7xLs01fR3YEc3DERiz5silj8tnGkFZytt1abEvl/GhUmCE0PMLaMPTa3Jk4HbKmRlHmu+gCftg==} + engines: {node: '>=12'} + + '@tanstack/virtual-core@3.17.2': + resolution: {integrity: sha512-w43MvWvmShpb6kIC9MOoLyUkLmRTLPjt61bHWs+X29hACSpX+n8DvgZ3qM7cUfflKlRRcHR9KVJE6TmcqnQvcA==} + '@tokenizer/inflate@0.4.1': resolution: {integrity: sha512-2mAv+8pkG6GIZiF1kNg1jAjh27IDxEPKwdGul3snfztFerfPGI1LjDezZp3i7BElXompqEtPmoPx6c2wgtWsOA==} engines: {node: '>=18'} @@ -2752,6 +3521,99 @@ packages: '@types/babel__traverse@7.28.0': resolution: {integrity: sha512-8PvcXf70gTDZBgt9ptxJ8elBeBjcLOAcOtoO/mPJjtji1+CdGbHgm77om1GrsPxsiE+uXIpNSK64UYaIwQXd4Q==} + '@types/d3-array@3.2.2': + resolution: {integrity: sha512-hOLWVbm7uRza0BYXpIIW5pxfrKe0W+D5lrFiAEYR+pb6w3N2SwSMaJbXdUfSEv+dT4MfHBLtn5js0LAWaO6otw==} + + '@types/d3-axis@3.0.6': + resolution: {integrity: sha512-pYeijfZuBd87T0hGn0FO1vQ/cgLk6E1ALJjfkC0oJ8cbwkZl3TpgS8bVBLZN+2jjGgg38epgxb2zmoGtSfvgMw==} + + '@types/d3-brush@3.0.6': + resolution: {integrity: sha512-nH60IZNNxEcrh6L1ZSMNA28rj27ut/2ZmI3r96Zd+1jrZD++zD3LsMIjWlvg4AYrHn/Pqz4CF3veCxGjtbqt7A==} + + '@types/d3-chord@3.0.6': + resolution: {integrity: sha512-LFYWWd8nwfwEmTZG9PfQxd17HbNPksHBiJHaKuY1XeqscXacsS2tyoo6OdRsjf+NQYeB6XrNL3a25E3gH69lcg==} + + '@types/d3-color@3.1.3': + resolution: {integrity: sha512-iO90scth9WAbmgv7ogoq57O9YpKmFBbmoEoCHDB2xMBY0+/KVrqAaCDyCE16dUspeOvIxFFRI+0sEtqDqy2b4A==} + + '@types/d3-contour@3.0.6': + resolution: {integrity: sha512-BjzLgXGnCWjUSYGfH1cpdo41/hgdWETu4YxpezoztawmqsvCeep+8QGfiY6YbDvfgHz/DkjeIkkZVJavB4a3rg==} + + '@types/d3-delaunay@6.0.4': + resolution: {integrity: sha512-ZMaSKu4THYCU6sV64Lhg6qjf1orxBthaC161plr5KuPHo3CNm8DTHiLw/5Eq2b6TsNP0W0iJrUOFscY6Q450Hw==} + + '@types/d3-dispatch@3.0.7': + resolution: {integrity: sha512-5o9OIAdKkhN1QItV2oqaE5KMIiXAvDWBDPrD85e58Qlz1c1kI/J0NcqbEG88CoTwJrYe7ntUCVfeUl2UJKbWgA==} + + '@types/d3-drag@3.0.7': + resolution: {integrity: sha512-HE3jVKlzU9AaMazNufooRJ5ZpWmLIoc90A37WU2JMmeq28w1FQqCZswHZ3xR+SuxYftzHq6WU6KJHvqxKzTxxQ==} + + '@types/d3-dsv@3.0.7': + resolution: {integrity: sha512-n6QBF9/+XASqcKK6waudgL0pf/S5XHPPI8APyMLLUHd8NqouBGLsU8MgtO7NINGtPBtk9Kko/W4ea0oAspwh9g==} + + '@types/d3-ease@3.0.2': + resolution: {integrity: sha512-NcV1JjO5oDzoK26oMzbILE6HW7uVXOHLQvHshBUW4UMdZGfiY6v5BeQwh9a9tCzv+CeefZQHJt5SRgK154RtiA==} + + '@types/d3-fetch@3.0.7': + resolution: {integrity: sha512-fTAfNmxSb9SOWNB9IoG5c8Hg6R+AzUHDRlsXsDZsNp6sxAEOP0tkP3gKkNSO/qmHPoBFTxNrjDprVHDQDvo5aA==} + + '@types/d3-force@3.0.10': + resolution: {integrity: sha512-ZYeSaCF3p73RdOKcjj+swRlZfnYpK1EbaDiYICEEp5Q6sUiqFaFQ9qgoshp5CzIyyb/yD09kD9o2zEltCexlgw==} + + '@types/d3-format@3.0.4': + resolution: {integrity: sha512-fALi2aI6shfg7vM5KiR1wNJnZ7r6UuggVqtDA+xiEdPZQwy/trcQaHnwShLuLdta2rTymCNpxYTiMZX/e09F4g==} + + '@types/d3-geo@3.1.0': + resolution: {integrity: sha512-856sckF0oP/diXtS4jNsiQw/UuK5fQG8l/a9VVLeSouf1/PPbBE1i1W852zVwKwYCBkFJJB7nCFTbk6UMEXBOQ==} + + '@types/d3-hierarchy@3.1.7': + resolution: {integrity: sha512-tJFtNoYBtRtkNysX1Xq4sxtjK8YgoWUNpIiUee0/jHGRwqvzYxkq0hGVbbOGSz+JgFxxRu4K8nb3YpG3CMARtg==} + + '@types/d3-interpolate@3.0.4': + resolution: {integrity: sha512-mgLPETlrpVV1YRJIglr4Ez47g7Yxjl1lj7YKsiMCb27VJH9W8NVM6Bb9d8kkpG/uAQS5AmbA48q2IAolKKo1MA==} + + '@types/d3-path@3.1.1': + resolution: {integrity: sha512-VMZBYyQvbGmWyWVea0EHs/BwLgxc+MKi1zLDCONksozI4YJMcTt8ZEuIR4Sb1MMTE8MMW49v0IwI5+b7RmfWlg==} + + '@types/d3-polygon@3.0.2': + resolution: {integrity: sha512-ZuWOtMaHCkN9xoeEMr1ubW2nGWsp4nIql+OPQRstu4ypeZ+zk3YKqQT0CXVe/PYqrKpZAi+J9mTs05TKwjXSRA==} + + '@types/d3-quadtree@3.0.6': + resolution: {integrity: sha512-oUzyO1/Zm6rsxKRHA1vH0NEDG58HrT5icx/azi9MF1TWdtttWl0UIUsjEQBBh+SIkrpd21ZjEv7ptxWys1ncsg==} + + '@types/d3-random@3.0.3': + resolution: {integrity: sha512-Imagg1vJ3y76Y2ea0871wpabqp613+8/r0mCLEBfdtqC7xMSfj9idOnmBYyMoULfHePJyxMAw3nWhJxzc+LFwQ==} + + '@types/d3-scale-chromatic@3.1.0': + resolution: {integrity: sha512-iWMJgwkK7yTRmWqRB5plb1kadXyQ5Sj8V/zYlFGMUBbIPKQScw+Dku9cAAMgJG+z5GYDoMjWGLVOvjghDEFnKQ==} + + '@types/d3-scale@4.0.9': + resolution: {integrity: sha512-dLmtwB8zkAeO/juAMfnV+sItKjlsw2lKdZVVy6LRr0cBmegxSABiLEpGVmSJJ8O08i4+sGR6qQtb6WtuwJdvVw==} + + '@types/d3-selection@3.0.11': + resolution: {integrity: sha512-bhAXu23DJWsrI45xafYpkQ4NtcKMwWnAC/vKrd2l+nxMFuvOT3XMYTIj2opv8vq8AO5Yh7Qac/nSeP/3zjTK0w==} + + '@types/d3-shape@3.1.8': + resolution: {integrity: sha512-lae0iWfcDeR7qt7rA88BNiqdvPS5pFVPpo5OfjElwNaT2yyekbM0C9vK+yqBqEmHr6lDkRnYNoTBYlAgJa7a4w==} + + '@types/d3-time-format@4.0.3': + resolution: {integrity: sha512-5xg9rC+wWL8kdDj153qZcsJ0FWiFt0J5RB6LYUNZjwSnesfblqrI/bJ1wBdJ8OQfncgbJG5+2F+qfqnqyzYxyg==} + + '@types/d3-time@3.0.4': + resolution: {integrity: sha512-yuzZug1nkAAaBlBBikKZTgzCeA+k1uy4ZFwWANOfKw5z5LRhV0gNA7gNkKm7HoK+HRN0wX3EkxGk0fpbWhmB7g==} + + '@types/d3-timer@3.0.2': + resolution: {integrity: sha512-Ps3T8E8dZDam6fUyNiMkekK3XUsaUEik+idO9/YjPtfj2qruF8tFBXS7XhtE4iIXBLxhmLjP3SXpLhVf21I9Lw==} + + '@types/d3-transition@3.0.9': + resolution: {integrity: sha512-uZS5shfxzO3rGlu0cC3bjmMFKsXv+SmZZcgp0KD22ts4uGXp5EVYGzu/0YdwZeKmddhcAccYtREJKkPfXkZuCg==} + + '@types/d3-zoom@3.0.8': + resolution: {integrity: sha512-iqMC4/YlFCSlO8+2Ii1GGGliCAY4XdeG748w5vQUbevlbDu0zSjH/+jojorQVBK/se0j6DUFNPBGSqD3YWYnDw==} + + '@types/d3@7.4.3': + resolution: {integrity: sha512-lZXZ9ckh5R8uiFVt8ogUNf+pIrK4EsWrx2Np75WvF/eTpJ0FMHNhjXk8CKEx/+gpHbNQyJWehbFaTvqmHWB3ww==} + '@types/debug@4.1.13': resolution: {integrity: sha512-KSVgmQmzMwPlmtljOomayoR89W4FynCAi3E8PPs7vmDVPe84hT+vGPKkJfThkmXs0x0jAaa9U8uW8bbfyS2fWw==} @@ -2761,12 +3623,12 @@ packages: '@types/estree@1.0.8': resolution: {integrity: sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==} + '@types/geojson@7946.0.16': + resolution: {integrity: sha512-6C8nqWur3j98U6+lXDfTUWIfgvZU+EumvpHKcYjujKH7woYyLj2sUmff0tRhrqM7BohUw7Pz3ZB1jj2gW9Fvmg==} + '@types/hast@3.0.4': resolution: {integrity: sha512-WPs+bbQw5aCj+x6laNGWLH3wviHtoCv/P3+otBhbOhJgG8qtpdAMlTCxLtsTWA7LH1Oh/bFCHsBn0TPS5m30EQ==} - '@types/js-yaml@4.0.9': - resolution: {integrity: sha512-k4MGaQl5TGo/iipqb2UDG2UwjXziSWkh0uysQelTlJpX1qGlpUZYm8PnO4DxG1qBomtJUdYJ6qR6xdIah10JLg==} - '@types/mdast@4.0.4': resolution: {integrity: sha512-kGaNbPh1k7AFzgpud/gMdvIm5xuECykRR+JnWKQno9TAXVa6WIVCGTPvYGekIDL4uwCZQSYbUxNBSb1aUo79oA==} @@ -2805,6 +3667,9 @@ packages: '@types/semver@7.7.1': resolution: {integrity: sha512-FmgJfu+MOcQ370SD0ev7EI8TlCAfKYU+B4m5T3yXc1CiRN94g/SZPtsCkk506aUDtlMnFZvasDwHHUcZUEaYuA==} + '@types/trusted-types@2.0.7': + resolution: {integrity: sha512-ScaPdn1dQczgbl0QFTeTOmVHFULt394XJgOQNoyVhZ6r2vLnMLJfBPd53SB52T/3G36VI1/g2MZaX0cwDuXsfw==} + '@types/unist@2.0.11': resolution: {integrity: sha512-CmBKiL6NNo/OqgmMn95Fk9Whlp2mtvIv+KNpQKN2F4SjvrEesubTRWGYSg+BnWZOnlCaSTU1sMpsBOzgbYhnsA==} @@ -2814,9 +3679,44 @@ packages: '@types/yauzl@2.10.3': resolution: {integrity: sha512-oJoftv0LSuaDZE3Le4DbKX+KS9G36NzOeSap90UIK0yMA/NhKJhqlSGtNDORNRaIbQfzjXDrQa0ytJ6mNRGz/Q==} + '@uiw/codemirror-extensions-basic-setup@4.25.10': + resolution: {integrity: sha512-P3vytLlpE62KYSWrMUnwDCv2lvaQDuDZzyj03mHntuHo5bSl34fRZpjTY3kQTPGuXHxkGSYpoPFFj+hMTqaaMQ==} + peerDependencies: + '@codemirror/autocomplete': '>=6.0.0' + '@codemirror/commands': '>=6.0.0' + '@codemirror/language': '>=6.0.0' + '@codemirror/lint': '>=6.0.0' + '@codemirror/search': '>=6.0.0' + '@codemirror/state': '>=6.0.0' + '@codemirror/view': '>=6.0.0' + + '@uiw/codemirror-theme-github@4.25.10': + resolution: {integrity: sha512-iMM2QT4FaebJMO4W7lXmxNkRPIjKzgY26wL0QG0Ugy0gzsnxoNz4zgNeFIblPA8rvrN3vOIhNNh4nk9UOlFKxA==} + + '@uiw/codemirror-themes@4.25.10': + resolution: {integrity: sha512-Fqiz1HIuDlDftcL+/O53V333UOH6MqQ84VbiQB5egn6u+uDwAqACp1FrdAoi4wgpR3b3TGW4Gr0wIYcrJSSz1A==} + peerDependencies: + '@codemirror/language': '>=6.0.0' + '@codemirror/state': '>=6.0.0' + '@codemirror/view': '>=6.0.0' + + '@uiw/react-codemirror@4.25.10': + resolution: {integrity: sha512-DzgSMwM5qzB7v1FIb4gEeriYt67iiay756/HIOM9mAbeOVK0MO7rqefHf0O5c0269pJKMW7AH9FjclExD23V9w==} + peerDependencies: + '@babel/runtime': '>=7.11.0' + '@codemirror/state': '>=6.0.0' + '@codemirror/theme-one-dark': '>=6.0.0' + '@codemirror/view': '>=6.0.0' + codemirror: '>=6.0.0' + react: '>=17.0.0' + react-dom: '>=17.0.0' + '@ungap/structured-clone@1.3.1': resolution: {integrity: sha512-mUFwbeTqrVgDQxFveS+df2yfap6iuP20NAKAsBt5jDEoOTDew+zwLAOilHCeQJOVSvmgCX4ogqIrA0mnyr08yQ==} + '@upsetjs/venn.js@2.0.0': + resolution: {integrity: sha512-WbBhLrooyePuQ1VZxrJjtLvTc4NVfpOyKx0sKqioq9bX1C1m7Jgykkn8gLrtwumBioXIqam8DLxp88Adbue6Hw==} + '@vitejs/plugin-react@4.7.0': resolution: {integrity: sha512-gUu9hwfWvvEDBBmgtAowQCojwZmJ5mcLn3aufeCsitijs3+f2NsrPtlAWIR6OPiqljl96GVCUbLe0HyqIpVaoA==} engines: {node: ^14.18.0 || >=16.0.0} @@ -2869,6 +3769,10 @@ packages: acp-http-client@0.4.2: resolution: {integrity: sha512-3wtPieF08YIU4vNXaoL5up/1D0if4i9IX3Ye5q/bwbcwg1BKsazIK/VNNfvN4ldbPjWul69IqIOpGRS3I0qo3Q==} + agent-base@6.0.2: + resolution: {integrity: sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==} + engines: {node: '>= 6.0.0'} + agent-base@7.1.4: resolution: {integrity: sha512-MnA+YT8fwfJPgBx3m60MNqakm30XOkyIoH1y6huTQvC0PwZG7ki8NacLBcrPbNoo8vEZy7Jpuk7+jMO+CUovTQ==} engines: {node: '>= 14'} @@ -2916,6 +3820,10 @@ packages: argparse@2.0.1: resolution: {integrity: sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==} + aria-hidden@1.2.6: + resolution: {integrity: sha512-ik3ZgC9dY/lYVVM++OISsaYDeg1tb0VtP5uL3ouh1koGOaUMDPpbFIei4JkFimWUFPn90sbMNMXQAIVOlnYKJA==} + engines: {node: '>=10'} + aria-query@5.3.2: resolution: {integrity: sha512-COROpnaoap1E2F000S62r6A60uHZnmlvomhfyT2DlTcrY1OrBKn2UhH7qn5wTC9zMvD0AY7csdPSNwKP+7WiQw==} engines: {node: '>= 0.4'} @@ -2944,16 +3852,14 @@ packages: resolution: {integrity: sha512-LElXdjswlqjWrPpJFg1Fx4wpkOCxj1TDHlSV4PlaRxHGWko024xICaa97ZkMfs6DRKlCguiAI+rbXv5GWwXIkg==} hasBin: true - astro-expressive-code@0.41.7: - resolution: {integrity: sha512-hUpogGc6DdAd+I7pPXsctyYPRBJDK7Q7d06s4cyP0Vz3OcbziP3FNzN0jZci1BpCvLn9675DvS7B9ctKKX64JQ==} - peerDependencies: - astro: ^4.0.0-beta || ^5.0.0-beta || ^3.3.0 || ^6.0.0-beta - astro@5.18.2: resolution: {integrity: sha512-TnFwLnAXty5MXKPDGuKXqK4AMBXG+FH6RUdK7Oyc3gyfNoFIthT+4eRbzOK43bdRlLaZuxgciDSjgtggZ3OtGQ==} engines: {node: 18.20.8 || ^20.3.0 || >=22.0.0, npm: '>=9.6.5', pnpm: '>=7.1.0'} hasBin: true + asynckit@0.4.0: + resolution: {integrity: sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==} + autoprefixer@10.5.0: resolution: {integrity: sha512-FMhOoZV4+qR6aTUALKX2rEqGG+oyATvwBt9IIzVR5rMa2HRWPkxf+P+PAJLD1I/H5/II+HuZcBJYEFBpq39ong==} engines: {node: ^10 || ^12 || >=14} @@ -2965,6 +3871,9 @@ packages: resolution: {integrity: sha512-wvUjBtSGN7+7SjNpq/9M2Tg350UZD3q62IFZLbRAR1bSMlCo1ZaeW+BJ+D090e4hIIZLBcTDWe4Mh4jvUDajzQ==} engines: {node: '>= 0.4'} + axios@1.18.1: + resolution: {integrity: sha512-3nTvFlvpn9Zu/RkHUqtc7/+al4UpRW5az71ap5zccp6e8RAYEzhMTecX8Dz1wWDYrPpUoB1HAQEGEAEvUr7S9g==} + axobject-query@4.1.0: resolution: {integrity: sha512-qIj0G9wZbMGNLjLmg1PT6v2mE9AH2zlnADJD/2tC6E00hgmhUOfEB6greHPAfLRSufHqROIUTkw6E+M3lH0PTQ==} engines: {node: '>= 0.4'} @@ -2994,12 +3903,6 @@ packages: resolution: {integrity: sha512-bopVNp6ugyA150DDuZfPFdt1KZ5a94ZDiwX4hMgZDzF+GttD80lEy8kj98kbyhLXnPvhtIo93mdnLIjpCAeeOw==} engines: {node: '>=10.0.0'} - bcp-47-match@2.0.3: - resolution: {integrity: sha512-JtTezzbAibu8G0R9op9zb3vcWZd9JF6M0xOYGPn0fNCd7wOpRB1mU2mH9T8gaBGbAAyIIVgB2G7xG0GP98zMAQ==} - - bcp-47@2.1.0: - resolution: {integrity: sha512-9IIS3UPrvIa1Ej+lVDdDwO7zLehjqsaByECw0bu2RRGP73jALm6FYbzI5gWbgHLvNdkvfXB5YrSbocZdOS0c0w==} - bcrypt-pbkdf@1.0.2: resolution: {integrity: sha512-qeFIXtP4MSoi6NLqO12WfqARWWuCKi2Rn/9hJLEmtB5yTNr9DqFWkJRCf2qShWzPeAMRnOgCrq0sg/KLv5ES9w==} @@ -3181,6 +4084,9 @@ packages: resolution: {integrity: sha512-Mz9QMT5fJe7bKI7MH31UilT5cEK5EHHRCccw/YRFsRY47AuNgaV6HY3rscp0/I4Q+tTW/5zoqpSeRRI54TkDWA==} engines: {node: '>= 0.10'} + class-variance-authority@0.7.1: + resolution: {integrity: sha512-Ka+9Trutv7G8M6WT6SeiRWz792K5qEqIGEGzXKhAE6xOWAY6pPH8U+9IY3oCMv6kqTmLsv7Xh/2w2RigkePMsg==} + cli-boxes@3.0.0: resolution: {integrity: sha512-/lzGpEWL/8PfI0BmBOPRwp0c/wFNX1RdUML3jK/RcSBA9T8mZDdQpqYBKtCFTOfQbwPqWEOpjqW+Fnayc0969g==} engines: {node: '>=10'} @@ -3201,6 +4107,15 @@ packages: resolution: {integrity: sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA==} engines: {node: '>=6'} + cmdk@1.1.1: + resolution: {integrity: sha512-Vsv7kFaXm+ptHDMZ7izaRsP70GgrW9NBNGswt9OZaVBLlE0SNpDq8eu/VGXyF9r7M0azK3Wy7OlYXsuyYLFzHg==} + peerDependencies: + react: ^18 || ^19 || ^19.0.0-rc + react-dom: ^18 || ^19 || ^19.0.0-rc + + codemirror@6.0.2: + resolution: {integrity: sha512-VhydHotNW5w1UGK0Qj96BwSk/Zqbp9WbnyK2W/eVMv4QyF41INRGpjUhFJY7/uDNuudSc33a/PKr4iDqRduvHw==} + collapse-white-space@2.1.0: resolution: {integrity: sha512-loKTxY1zCOuG4j9f6EPnuyyYkf58RnhhWTvRoZEokgB+WbdXehfjFviyOVYkqzEWz1Q5kRiZdBYS5SwxbQYwzw==} @@ -3218,6 +4133,10 @@ packages: resolution: {integrity: sha512-1rXeuUUiGGrykh+CeBdu5Ie7OJwinCgQY0bc7GCRxy5xVHy+moaqkpL/jqQq0MtQOeYcrqEz4abc5f0KtU7W4A==} engines: {node: '>=12.5.0'} + combined-stream@1.0.8: + resolution: {integrity: sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==} + engines: {node: '>= 0.8'} + comma-separated-tokens@2.0.3: resolution: {integrity: sha512-Fu4hJdvzeylCfQPp9SGWidpzrMs7tTrlu6Vb8XGaRGck8QSNZJJp538Wrb60Lax4fPwR64ViY468OIUTbRlGZg==} @@ -3233,6 +4152,14 @@ packages: resolution: {integrity: sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA==} engines: {node: '>= 6'} + commander@7.2.0: + resolution: {integrity: sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw==} + engines: {node: '>= 10'} + + commander@8.3.0: + resolution: {integrity: sha512-OkTL9umf+He2DZkUq8f8J9of7yL6RJKI24dVITBmNfZBmri9zYZQrKkuXiKhyfPSu8tUhnVBB1iKXevvnlR4Ww==} + engines: {node: '>= 12'} + common-ancestor-path@1.0.1: resolution: {integrity: sha512-L3sHRo1pXXEqX8VU28kfgUY+YGsk09hPqZiZmLacNib6XNTCM8ubYeT7ryXQw8asB1sKgcU5lkB7ONug08aB8w==} @@ -3272,6 +4199,9 @@ packages: resolution: {integrity: sha512-ei8Aos7ja0weRpFzJnEA9UHJ/7XQmqglbRwnf2ATjcB9Wq874VKH9kfjjirM6UhU2/E5fFYadylyhFldcqSidQ==} engines: {node: '>=18'} + core-js@3.49.0: + resolution: {integrity: sha512-es1U2+YTtzpwkxVLwAFdSpaIMyQaq0PBgm3YD1W3Qpsn1NAmO3KSgZfu+oGSWVu6NvLHoHCV/aYcsE5wiB7ALg==} + core-util-is@1.0.3: resolution: {integrity: sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==} @@ -3279,6 +4209,12 @@ packages: resolution: {integrity: sha512-tJtZBBHA6vjIAaF6EnIaq6laBBP9aq/Y3ouVJjEfoHbRBcHBAHYcMh/w8LDrk2PvIMMq8gmopa5D4V8RmbrxGw==} engines: {node: '>= 0.10'} + cose-base@1.0.3: + resolution: {integrity: sha512-s9whTXInMSgAp/NVXVNuVxVKzGH2qck3aQlVHxDCdAEPgtMKwc4Wq6/QKhgdEdgbLSi9rBTAcPoRa6JpiG4ksg==} + + cose-base@2.2.0: + resolution: {integrity: sha512-AzlgcsCbUMymkADOJtQm3wO9S3ltPfYOFD5033keQn9NJzIbtnZj+UdBJe7DYml/8TdbtHJW3j58SOnKhWY/5g==} + cpu-features@0.0.10: resolution: {integrity: sha512-9IkYqtX3YHPCzoVg1Py+o9057a3i0fp7S530UWokCSaFVTc7CwXPRiOjRjBQQ18ZCNafx78YfnG+HALxtVmOGA==} engines: {node: '>=10.0.0'} @@ -3295,6 +4231,9 @@ packages: create-require@1.1.1: resolution: {integrity: sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==} + crelt@1.0.7: + resolution: {integrity: sha512-aK6BbWfhf4U/wCcLHKPJl/xa6VkVstRaPywWtMKGwuOLc/wZTyQYuoxgvZnNsBvv7Kg3YTBQYYBCggcviQczuA==} + cross-spawn@7.0.6: resolution: {integrity: sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==} engines: {node: '>= 8'} @@ -3309,9 +4248,6 @@ packages: css-select@5.2.2: resolution: {integrity: sha512-TizTzUddG/xYLA3NXodFM0fSbNizXjOKhqiQQwvhlspadZokn1KDy0NZFS0wuEubIYAV5/c1/lAr0TaaFXEXzw==} - css-selector-parser@3.3.0: - resolution: {integrity: sha512-Y2asgMGFqJKF4fq4xHDSlFYIkeVfRsm69lQC1q9kbEsH5XtnINTMrweLkjYMeaUgiXBy/uvKeO/a1JHTNnmB2g==} - css-tree@2.2.1: resolution: {integrity: sha512-OA0mILzGc1kCOCSJerOeqDxDQ4HOh+G8NbOJFOTgOCzpw7fCBubk0fEyxp8AgOL/jvLgYA/uV0cMbe43ElF1JA==} engines: {node: ^10 || ^12.20.0 || ^14.13.0 || >=15.0.0, npm: '>=7.0.0'} @@ -3336,6 +4272,162 @@ packages: csstype@3.2.3: resolution: {integrity: sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ==} + cytoscape-cose-bilkent@4.1.0: + resolution: {integrity: sha512-wgQlVIUJF13Quxiv5e1gstZ08rnZj2XaLHGoFMYXz7SkNfCDOOteKBE6SYRfA9WxxI/iBc3ajfDoc6hb/MRAHQ==} + peerDependencies: + cytoscape: ^3.2.0 + + cytoscape-fcose@2.2.0: + resolution: {integrity: sha512-ki1/VuRIHFCzxWNrsshHYPs6L7TvLu3DL+TyIGEsRcvVERmxokbf5Gdk7mFxZnTdiGtnA4cfSmjZJMviqSuZrQ==} + peerDependencies: + cytoscape: ^3.2.0 + + cytoscape@3.34.0: + resolution: {integrity: sha512-62rNSrioXw93uliKFBwjukeQyeWwH2PqDrTac31r2P6464u3AUvTk0xS4LVvT251g7IgkFunrI48ZEZGjywSOg==} + engines: {node: '>=0.10'} + + d3-array@2.12.1: + resolution: {integrity: sha512-B0ErZK/66mHtEsR1TkPEEkwdy+WDesimkM5gpZr5Dsg54BiTA5RXtYW5qTLIAcekaS9xfZrzBLF/OAkB3Qn1YQ==} + + d3-array@3.2.4: + resolution: {integrity: sha512-tdQAmyA18i4J7wprpYq8ClcxZy3SC31QMeByyCFyRt7BVHdREQZ5lpzoe5mFEYZUWe+oq8HBvk9JjpibyEV4Jg==} + engines: {node: '>=12'} + + d3-axis@3.0.0: + resolution: {integrity: sha512-IH5tgjV4jE/GhHkRV0HiVYPDtvfjHQlQfJHs0usq7M30XcSBvOotpmH1IgkcXsO/5gEQZD43B//fc7SRT5S+xw==} + engines: {node: '>=12'} + + d3-brush@3.0.0: + resolution: {integrity: sha512-ALnjWlVYkXsVIGlOsuWH1+3udkYFI48Ljihfnh8FZPF2QS9o+PzGLBslO0PjzVoHLZ2KCVgAM8NVkXPJB2aNnQ==} + engines: {node: '>=12'} + + d3-chord@3.0.1: + resolution: {integrity: sha512-VE5S6TNa+j8msksl7HwjxMHDM2yNK3XCkusIlpX5kwauBfXuyLAtNg9jCp/iHH61tgI4sb6R/EIMWCqEIdjT/g==} + engines: {node: '>=12'} + + d3-color@3.1.0: + resolution: {integrity: sha512-zg/chbXyeBtMQ1LbD/WSoW2DpC3I0mpmPdW+ynRTj/x2DAWYrIY7qeZIHidozwV24m4iavr15lNwIwLxRmOxhA==} + engines: {node: '>=12'} + + d3-contour@4.0.2: + resolution: {integrity: sha512-4EzFTRIikzs47RGmdxbeUvLWtGedDUNkTcmzoeyg4sP/dvCexO47AaQL7VKy/gul85TOxw+IBgA8US2xwbToNA==} + engines: {node: '>=12'} + + d3-delaunay@6.0.4: + resolution: {integrity: sha512-mdjtIZ1XLAM8bm/hx3WwjfHt6Sggek7qH043O8KEjDXN40xi3vx/6pYSVTwLjEgiXQTbvaouWKynLBiUZ6SK6A==} + engines: {node: '>=12'} + + d3-dispatch@3.0.1: + resolution: {integrity: sha512-rzUyPU/S7rwUflMyLc1ETDeBj0NRuHKKAcvukozwhshr6g6c5d8zh4c2gQjY2bZ0dXeGLWc1PF174P2tVvKhfg==} + engines: {node: '>=12'} + + d3-drag@3.0.0: + resolution: {integrity: sha512-pWbUJLdETVA8lQNJecMxoXfH6x+mO2UQo8rSmZ+QqxcbyA3hfeprFgIT//HW2nlHChWeIIMwS2Fq+gEARkhTkg==} + engines: {node: '>=12'} + + d3-dsv@3.0.1: + resolution: {integrity: sha512-UG6OvdI5afDIFP9w4G0mNq50dSOsXHJaRE8arAS5o9ApWnIElp8GZw1Dun8vP8OyHOZ/QJUKUJwxiiCCnUwm+Q==} + engines: {node: '>=12'} + hasBin: true + + d3-ease@3.0.1: + resolution: {integrity: sha512-wR/XK3D3XcLIZwpbvQwQ5fK+8Ykds1ip7A2Txe0yxncXSdq1L9skcG7blcedkOX+ZcgxGAmLX1FrRGbADwzi0w==} + engines: {node: '>=12'} + + d3-fetch@3.0.1: + resolution: {integrity: sha512-kpkQIM20n3oLVBKGg6oHrUchHM3xODkTzjMoj7aWQFq5QEM+R6E4WkzT5+tojDY7yjez8KgCBRoj4aEr99Fdqw==} + engines: {node: '>=12'} + + d3-force@3.0.0: + resolution: {integrity: sha512-zxV/SsA+U4yte8051P4ECydjD/S+qeYtnaIyAs9tgHCqfguma/aAQDjo85A9Z6EKhBirHRJHXIgJUlffT4wdLg==} + engines: {node: '>=12'} + + d3-format@3.1.2: + resolution: {integrity: sha512-AJDdYOdnyRDV5b6ArilzCPPwc1ejkHcoyFarqlPqT7zRYjhavcT3uSrqcMvsgh2CgoPbK3RCwyHaVyxYcP2Arg==} + engines: {node: '>=12'} + + d3-geo@3.1.1: + resolution: {integrity: sha512-637ln3gXKXOwhalDzinUgY83KzNWZRKbYubaG+fGVuc/dxO64RRljtCTnf5ecMyE1RIdtqpkVcq0IbtU2S8j2Q==} + engines: {node: '>=12'} + + d3-hierarchy@3.1.2: + resolution: {integrity: sha512-FX/9frcub54beBdugHjDCdikxThEqjnR93Qt7PvQTOHxyiNCAlvMrHhclk3cD5VeAaq9fxmfRp+CnWw9rEMBuA==} + engines: {node: '>=12'} + + d3-interpolate@3.0.1: + resolution: {integrity: sha512-3bYs1rOD33uo8aqJfKP3JWPAibgw8Zm2+L9vBKEHJ2Rg+viTR7o5Mmv5mZcieN+FRYaAOWX5SJATX6k1PWz72g==} + engines: {node: '>=12'} + + d3-path@1.0.9: + resolution: {integrity: sha512-VLaYcn81dtHVTjEHd8B+pbe9yHWpXKZUC87PzoFmsFrJqgFwDe/qxfp5MlfsfM1V5E/iVt0MmEbWQ7FVIXh/bg==} + + d3-path@3.1.0: + resolution: {integrity: sha512-p3KP5HCf/bvjBSSKuXid6Zqijx7wIfNW+J/maPs+iwR35at5JCbLUT0LzF1cnjbCHWhqzQTIN2Jpe8pRebIEFQ==} + engines: {node: '>=12'} + + d3-polygon@3.0.1: + resolution: {integrity: sha512-3vbA7vXYwfe1SYhED++fPUQlWSYTTGmFmQiany/gdbiWgU/iEyQzyymwL9SkJjFFuCS4902BSzewVGsHHmHtXg==} + engines: {node: '>=12'} + + d3-quadtree@3.0.1: + resolution: {integrity: sha512-04xDrxQTDTCFwP5H6hRhsRcb9xxv2RzkcsygFzmkSIOJy3PeRJP7sNk3VRIbKXcog561P9oU0/rVH6vDROAgUw==} + engines: {node: '>=12'} + + d3-random@3.0.1: + resolution: {integrity: sha512-FXMe9GfxTxqd5D6jFsQ+DJ8BJS4E/fT5mqqdjovykEB2oFbTMDVdg1MGFxfQW+FBOGoB++k8swBrgwSHT1cUXQ==} + engines: {node: '>=12'} + + d3-sankey@0.12.3: + resolution: {integrity: sha512-nQhsBRmM19Ax5xEIPLMY9ZmJ/cDvd1BG3UVvt5h3WRxKg5zGRbvnteTyWAbzeSvlh3tW7ZEmq4VwR5mB3tutmQ==} + + d3-scale-chromatic@3.1.0: + resolution: {integrity: sha512-A3s5PWiZ9YCXFye1o246KoscMWqf8BsD9eRiJ3He7C9OBaxKhAd5TFCdEx/7VbKtxxTsu//1mMJFrEt572cEyQ==} + engines: {node: '>=12'} + + d3-scale@4.0.2: + resolution: {integrity: sha512-GZW464g1SH7ag3Y7hXjf8RoUuAFIqklOAq3MRl4OaWabTFJY9PN/E1YklhXLh+OQ3fM9yS2nOkCoS+WLZ6kvxQ==} + engines: {node: '>=12'} + + d3-selection@3.0.0: + resolution: {integrity: sha512-fmTRWbNMmsmWq6xJV8D19U/gw/bwrHfNXxrIN+HfZgnzqTHp9jOmKMhsTUjXOJnZOdZY9Q28y4yebKzqDKlxlQ==} + engines: {node: '>=12'} + + d3-shape@1.3.7: + resolution: {integrity: sha512-EUkvKjqPFUAZyOlhY5gzCxCeI0Aep04LwIRpsZ/mLFelJiUfnK56jo5JMDSE7yyP2kLSb6LtF+S5chMk7uqPqw==} + + d3-shape@3.2.0: + resolution: {integrity: sha512-SaLBuwGm3MOViRq2ABk3eLoxwZELpH6zhl3FbAoJ7Vm1gofKx6El1Ib5z23NUEhF9AsGl7y+dzLe5Cw2AArGTA==} + engines: {node: '>=12'} + + d3-time-format@4.1.0: + resolution: {integrity: sha512-dJxPBlzC7NugB2PDLwo9Q8JiTR3M3e4/XANkreKSUxF8vvXKqm1Yfq4Q5dl8budlunRVlUUaDUgFt7eA8D6NLg==} + engines: {node: '>=12'} + + d3-time@3.1.0: + resolution: {integrity: sha512-VqKjzBLejbSMT4IgbmVgDjpkYrNWUYJnbCGo874u7MMKIWsILRX+OpX/gTk8MqjpT1A/c6HY2dCA77ZN0lkQ2Q==} + engines: {node: '>=12'} + + d3-timer@3.0.1: + resolution: {integrity: sha512-ndfJ/JxxMd3nw31uyKoY2naivF+r29V+Lc0svZxe1JvvIRmi8hUsrMvdOwgS1o6uBHmiz91geQ0ylPP0aj1VUA==} + engines: {node: '>=12'} + + d3-transition@3.0.1: + resolution: {integrity: sha512-ApKvfjsSR6tg06xrL434C0WydLr7JewBB3V+/39RMHsaXTOG0zmt/OAXeng5M5LBm0ojmxJrpomQVZ1aPvBL4w==} + engines: {node: '>=12'} + peerDependencies: + d3-selection: 2 - 3 + + d3-zoom@3.0.0: + resolution: {integrity: sha512-b8AmV3kfQaqWAuacbPuNbL6vahnOJflOhexLzMMNLga62+/nh0JzvJ0aO/5a5MVgUFGS7Hu1P9P03o3fJkDCyw==} + engines: {node: '>=12'} + + d3@7.9.0: + resolution: {integrity: sha512-e1U46jVP+w7Iut8Jt8ri1YsPOvFpg46k+K8TpCb0P+zjCkjkPnV7WzfDJzMHy1LnA+wj5pLT1wjO901gLXeEhA==} + engines: {node: '>=12'} + + dagre-d3-es@7.0.14: + resolution: {integrity: sha512-P4rFMVq9ESWqmOgK+dlXvOtLwYg0i7u0HBGJER0LZDJT2VHIPAMZ/riPxqJceWMStH5+E61QxFra9kIS3AqdMg==} + data-uri-to-buffer@4.0.1: resolution: {integrity: sha512-0R9ikRb668HB7QDxT1vkpuUBtqc53YyAwMwGeUFKRojY/NWKvdZ+9UYtRfGmhqNbRkTSVpMbmyhXipFFv2cb/A==} engines: {node: '>= 12'} @@ -3344,6 +4436,12 @@ packages: resolution: {integrity: sha512-7hvf7/GW8e86rW0ptuwS3OcBGDjIi6SZva7hCyWC0yYry2cOPmLIjXAUHI6DK2HsnwJd9ifmt57i8eV2n4YNpw==} engines: {node: '>= 14'} + date-fns@4.4.0: + resolution: {integrity: sha512-+1UMbeh68lH1SegH83CGWwpb6OHHbpSgr3+s5Eww5M4CAgswBpoWS0AjTOfEJ33HiYKz1hdj/KTFprzXHmq/6w==} + + dayjs@1.11.21: + resolution: {integrity: sha512-98IT+HOahAisibz/yjKbzuOBwYcjJ7BCLPzARyHiyEBmRz4fatF+KPJszEHXsGYjUG234aH/cOjW1wwTbKUZlA==} + debug@4.4.3: resolution: {integrity: sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==} engines: {node: '>=6.0'} @@ -3353,9 +4451,20 @@ packages: supports-color: optional: true + decimal.js-light@2.5.1: + resolution: {integrity: sha512-qIMFpTMZmny+MMIitAB6D7iVPEorVw6YQRWkvarTkT4tBeSLLiHzcwj6q0MmYSFCiVpiqPJTJEYIrpcPzVEIvg==} + decode-named-character-reference@1.3.0: resolution: {integrity: sha512-GtpQYB283KrPp6nRw50q3U9/VfOutZOe103qlN7BPP6Ad27xYnOIWv4lPzo8HCAL+mMZofJ9KEy30fq6MfaK6Q==} + dedent@1.7.2: + resolution: {integrity: sha512-WzMx3mW98SN+zn3hgemf4OzdmyNhhhKz5Ay0pUfQiMQ3e1g+xmTJWp/pKdwKVXhdSkAEGIIzqeuWrL3mV/AXbA==} + peerDependencies: + babel-plugin-macros: ^3.1.0 + peerDependenciesMeta: + babel-plugin-macros: + optional: true + deep-eql@5.0.2: resolution: {integrity: sha512-h5k/5U50IJJFpzfL6nO9jaaumfjO/f2NjK/oYB2Djzm4p9L+3T9qWpZqZ2hAbLPuuYq9wrU08WQyBTL5GbPk5Q==} engines: {node: '>=6'} @@ -3375,6 +4484,13 @@ packages: resolution: {integrity: sha512-TllpMR/t0M5sqCXfj85i4XaAzxmS5tVA16dqvdkMwGmzI+dXLXnw3J+3Vdv7VKw+ThlTMboK6i9rnZ6Nntj5CQ==} engines: {node: '>= 14'} + delaunator@5.1.0: + resolution: {integrity: sha512-AGrQ4QSgssa1NGmWmLPqN5NY2KajF5MqxetNEO+o0n3ZwZZeTmt7bBnvzHWrmkZFxGgr4HdyFgelzgi06otLuQ==} + + delayed-stream@1.0.0: + resolution: {integrity: sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==} + engines: {node: '>=0.4.0'} + depd@2.0.0: resolution: {integrity: sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==} engines: {node: '>= 0.8'} @@ -3393,6 +4509,9 @@ packages: resolution: {integrity: sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==} engines: {node: '>=8'} + detect-node-es@1.1.0: + resolution: {integrity: sha512-ypdmJU/TbBby2Dxibuv7ZLW3Bs1QEmM7nHjEANfohJLvE0XVujisn1qPJcZxg+qDucsr+bP6fLD1rPS3AhJ7EQ==} + deterministic-object-hash@2.0.2: resolution: {integrity: sha512-KxektNH63SrbfUyDiwXqRb1rLwKt33AmMv+5Nhsw1kqZ13SJBRTgZHtGbE+hH3a1mVW1cz+4pqSWVPAtLVXTzQ==} engines: {node: '>=18'} @@ -3413,10 +4532,6 @@ packages: diffie-hellman@5.0.3: resolution: {integrity: sha512-kqag/Nl+f3GwyK25fhUMYj81BUOrZ9IuJsjIcDE5icNM9FJHAVm3VcUDxdLPoQtTuUylWm6ZIknYJwwaPxsUzg==} - direction@2.0.1: - resolution: {integrity: sha512-9S6m9Sukh1cZNknO1CWAr2QAWsbKLafQiyM5gZ7VgXHeuaoUwffKN4q6NC4A/Mf9iiPlOXQEKW/Mv/mh9/3YFA==} - hasBin: true - dlv@1.1.3: resolution: {integrity: sha512-+HlytyjlPKnIG8XuRG8WvmBP8xs8P71y+SKKS6ZXWoEgLuePxtDoUEiH7WkdePWrQ5JBpE6aoVqfZfJUQkjXwA==} @@ -3428,6 +4543,9 @@ packages: resolution: {integrity: sha512-8L/P9JynLBiG7/coiA4FlQXegHltRqS0a+KqI44P1zgQh8QLHTg7FKOwhkBgSJwZTeHsq30WRoVFLuwkfK0YFg==} engines: {node: '>= 8.0'} + dom-helpers@5.2.1: + resolution: {integrity: sha512-nRCa7CK3VTrM2NmGkIy4cbK7IZlgBE/PYMn55rrXefr5xXDP0LdtfPnblFDoVdcAfslJ7or6iqAUnx0CCGIWQA==} + dom-serializer@2.0.0: resolution: {integrity: sha512-wIkAryiqt/nV5EQKqQpo3SToSOV9J0DnbJqwK7Wv/Trc92zIAYZ4FlMu+JPFW1DfGFt81ZTCGgDEabffXeLyJg==} @@ -3442,6 +4560,9 @@ packages: resolution: {integrity: sha512-cgwlv/1iFQiFnU96XXgROh8xTeetsnJiDsTc7TYCLFd9+/WNkIqPTxiM/8pSd8VIrhXGTf1Ny1q1hquVqDJB5w==} engines: {node: '>= 4'} + dompurify@3.4.11: + resolution: {integrity: sha512-zhlUV12GsaRzMsf9q5M254YhA4+VuF0fG+QFqu6aYpoGlKtz+w8//jBcGVYBgQkR5GHjUomejY84AV+/uPbWdw==} + domutils@3.2.2: resolution: {integrity: sha512-6kZKyUajlDuqlHKVX1w7gyslj9MPIXzIFiz/rGu35uC1wMi+kMhQwGhl4lt9unC9Vb9INnY9Z3/ZA3+FhASLaw==} @@ -3507,6 +4628,13 @@ packages: resolution: {integrity: sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==} engines: {node: '>= 0.4'} + es-set-tostringtag@2.1.0: + resolution: {integrity: sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==} + engines: {node: '>= 0.4'} + + es-toolkit@1.49.0: + resolution: {integrity: sha512-G5iZ6Pc/FNRY/soKZHC+TxGDD83rHUDXxzaWhGCX44vAv/tMs56WMusnm/KMNK+luUPsgA9U28cGr4RDlSzL2g==} + esast-util-from-estree@2.0.0: resolution: {integrity: sha512-4CyanoAudUSBAn5K13H4JhsMH6L9ZP7XbLVe/dKybkxMO7eDyLsT8UHl9TRNrU2Gr9nz+FovfSIjuXWJ81uVwQ==} @@ -3568,6 +4696,9 @@ packages: estree-util-to-js@2.0.0: resolution: {integrity: sha512-WDF+xj5rRWmD5tj6bIqRi6CkLIXbbNQUcxQHzGysQzvHmdYG2G7p/Tf0J0gpxGgkeMZNTIjT/AoSvC9Xehcgdg==} + estree-util-visit@1.2.1: + resolution: {integrity: sha512-xbgqcrkIVbIG+lI/gzbvd9SGTJL4zqJKBFttUl5pP27KhAjtMKbX/mQXJ7qgyXpMgVy/zvpm0xoQQaGL8OloOw==} + estree-util-visit@2.0.0: resolution: {integrity: sha512-m5KgiH85xAhhW8Wta0vShLcUvOsh3LLPI2YVwcbio1l7E09NTLL1EyMZFM1OyWowoH0skScNbhOPl4kcBgzTww==} @@ -3585,6 +4716,9 @@ packages: resolution: {integrity: sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==} engines: {node: '>= 0.6'} + eventemitter3@4.0.7: + resolution: {integrity: sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw==} + eventemitter3@5.0.4: resolution: {integrity: sha512-mlsTRyGaPBjPedk6Bvw+aqbsXDtoAyAzm5MO7JgU+yVRyMQ5O8bD4Kcci7BS85f93veegeCPkL8R4GLClnjLFw==} @@ -3621,9 +4755,6 @@ packages: resolution: {integrity: sha512-hIS4idWWai69NezIdRt2xFVofaF4j+6INOpJlVOLDO8zXGpUVEVzIYk12UUi2JzjEzWL3IOAxcTubgz9Po0yXw==} engines: {node: '>= 18'} - expressive-code@0.41.7: - resolution: {integrity: sha512-2wZjC8OQ3TaVEMcBtYY4Va3lo6J+Ai9jf3d4dbhURMJcU4Pbqe6EcHe424MIZI0VHUA1bR6xdpoHYi3yxokWqA==} - extend@3.0.2: resolution: {integrity: sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==} @@ -3635,6 +4766,10 @@ packages: fast-deep-equal@3.1.3: resolution: {integrity: sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==} + fast-equals@5.4.0: + resolution: {integrity: sha512-jt2DW/aNFNwke7AUd+Z+e6pz39KO5rzdbbFCg2sGafS4mk13MI7Z8O5z9cADNn5lhGODIgLwug6TZO2ctf7kcw==} + engines: {node: '>=6.0.0'} + fast-glob@3.3.3: resolution: {integrity: sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg==} engines: {node: '>=8.6.0'} @@ -3661,6 +4796,9 @@ packages: resolution: {integrity: sha512-7yAQpD2UMJzLi1Dqv7qFYnPbaPx7ZfFK6PiIxQ4PfkGPyNyl2Ugx+a/umUonmKqjhM4DnfbMvdX6otXq83soQQ==} engines: {node: ^12.20 || >= 14.13} + fflate@0.4.8: + resolution: {integrity: sha512-FJqqoDBR00Mdj9ppamLa/Y7vxm+PRmNWA67N846RvsoYVMKB4q3y/de5PA7gUmRMYK/8CMz2GDZQmCRN1wBcWA==} + file-type@21.3.4: resolution: {integrity: sha512-Ievi/yy8DS3ygGvT47PjSfdFoX+2isQueoYP1cntFW1JLYAuS4GD7NUPGg4zv2iZfV52uDyk5w5Z0TdpRS6Q1g==} engines: {node: '>=20'} @@ -3681,6 +4819,15 @@ packages: resolution: {integrity: sha512-9UbaD6XdAL97+k/n+N7JwX46K/M6Zc6KcFYskrYL8wbBV/Uyk0CTAMY0VT+qiK5PM7AIc9aTWYtq65U7T+aCNQ==} engines: {node: '>=8'} + follow-redirects@1.16.0: + resolution: {integrity: sha512-y5rN/uOsadFT/JfYwhxRS5R7Qce+g3zG97+JrtFZlC9klX/W5hD7iiLzScI4nZqUS7DNUdhPgw4xI8W2LuXlUw==} + engines: {node: '>=4.0'} + peerDependencies: + debug: '*' + peerDependenciesMeta: + debug: + optional: true + fontace@0.4.1: resolution: {integrity: sha512-lDMvbAzSnHmbYMTEld5qdtvNH2/pWpICOqpean9IgC7vUbUJc3k+k5Dokp85CegamqQpFbXf0rAVkbzpyTA8aw==} @@ -3696,6 +4843,10 @@ packages: resolution: {integrity: sha512-gIXjKqtFuWEgzFRJA9WCQeSJLZDjgJUOMCMzxtvFq/37KojM1BFGufqsCy0r4qSQmYLsZYMeyRqzIWOMup03sw==} engines: {node: '>=14'} + form-data@4.0.6: + resolution: {integrity: sha512-vKatAh4SlVfgbv+YtmhiRjhEMJsYpsG1Y2rMQtR+SVSbytsSD1YGzDIcrAJmdFec88u/+VoGmxnl+80gL1tRCQ==} + engines: {node: '>= 6'} + formdata-polyfill@4.0.10: resolution: {integrity: sha512-buewHzMvYL29jdeQTVILecSaZKnt/RJWjoZCF5OW60Z67/GmSLBkOFM7qh1PI3zFNtJbaZL5eQu1vLfazOwj4g==} engines: {node: '>=12.20.0'} @@ -3707,6 +4858,20 @@ packages: fraction.js@5.3.4: resolution: {integrity: sha512-1X1NTtiJphryn/uLQz3whtY6jK3fTqoE3ohKs0tT+Ujr1W59oopxmoEh7Lu5p6vBaPbgoM0bzveAW4Qi5RyWDQ==} + framer-motion@11.18.2: + resolution: {integrity: sha512-5F5Och7wrvtLVElIpclDT0CBzMVg3dL22B64aZwHtsIY8RB4mXICLrkajK4G9R+ieSAGcgrLeae2SeUTg2pr6w==} + peerDependencies: + '@emotion/is-prop-valid': '*' + react: ^18.0.0 || ^19.0.0 + react-dom: ^18.0.0 || ^19.0.0 + peerDependenciesMeta: + '@emotion/is-prop-valid': + optional: true + react: + optional: true + react-dom: + optional: true + framer-motion@12.40.0: resolution: {integrity: sha512-uaBd3qC1v3KQqBEjwTUd183K6PbS+j0yR9w9VmEOLWA/tnUcSn8Xa3uck7t4dgpDoUss8xQTcj8W2L07lrnLFg==} peerDependencies: @@ -3741,6 +4906,10 @@ packages: function-bind@1.1.2: resolution: {integrity: sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==} + fuse.js@7.4.2: + resolution: {integrity: sha512-LVbzjD4WA6UP5B1UnP8wuaXJiLnqMdM/E4fiJXTJ5haJ5b/MBNsK29h2fm6swEoQaVQjvYFWKLE2RanyZIoRVQ==} + engines: {node: '>=10'} + gaxios@7.1.5: resolution: {integrity: sha512-5FZy72Rh8LhtjmvDrKkI+lVhrsQrVKVsItxMoDm5mNQE+xR0WVIIs+jzPSJgBvKVsLi24fZhXJIsNI0bihDzFg==} engines: {node: '>=18'} @@ -3769,6 +4938,10 @@ packages: resolution: {integrity: sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==} engines: {node: '>= 0.4'} + get-nonce@1.0.1: + resolution: {integrity: sha512-FJhYRoDaiatfEkUK8HKlicmu/3SGFD51q3itKDGoSTysQJBnfOcxU5GxnhE1E6soB76MbT0MBtnKJuXyAx+96Q==} + engines: {node: '>=6'} + get-port@7.2.0: resolution: {integrity: sha512-afP4W205ONCuMoPBqcR6PSXnzX35KTcJygfJfcp+QY+uwm3p20p1YczWXhlICIzGMCxYBQcySEcOgsJcrkyobg==} engines: {node: '>=16'} @@ -3830,6 +5003,9 @@ packages: h3@1.15.11: resolution: {integrity: sha512-L3THSe2MPeBwgIZVSH5zLdBBU90TOxarvhK9d04IDY2AmVS8j2Jz2LIWtwsGOU3lu2I5jCN7FNvVfY2+XyF+mg==} + hachure-fill@0.5.2: + resolution: {integrity: sha512-3GKBOn+m2LX9iq+JC1064cSFprJY4jL1jCXTcpnfER5HYE2l/4EfWSGzkPa/ZDBmYI0ZOEj5VHV/eKnPGkHuOg==} + has-flag@4.0.0: resolution: {integrity: sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==} engines: {node: '>=8'} @@ -3860,11 +5036,15 @@ packages: resolution: {integrity: sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==} engines: {node: '>= 0.4'} - hast-util-embedded@3.0.0: - resolution: {integrity: sha512-naH8sld4Pe2ep03qqULEtvYr7EjrLK2QHY8KJR6RJkTUjPGObe1vnx585uzem2hGra+s1q08DZZpfgDVYRbaXA==} + hasown@2.0.4: + resolution: {integrity: sha512-T2UbfbBEF32wiepXIsMlTW9+dDYC6wMh/t/vYA4tuOMKqWz/n3vr1NFSxQiyP+zk2mXsoMA/i/7qV6LKut1t1A==} + engines: {node: '>= 0.4'} + + hast-util-from-dom@5.0.1: + resolution: {integrity: sha512-N+LqofjR2zuzTjCPzyDUdSshy4Ma6li7p/c3pA78uTwzFgENbgbUrm2ugwsOdcjI1muO+o6Dgzp9p8WHtn/39Q==} - hast-util-format@1.1.0: - resolution: {integrity: sha512-yY1UDz6bC9rDvCWHpx12aIBGRG7krurX0p0Fm6pT547LwDIZZiNr8a+IHDogorAdreULSEzP82Nlv5SZkHZcjA==} + hast-util-from-html-isomorphic@2.0.0: + resolution: {integrity: sha512-zJfpXq44yff2hmE0XmwEOzdWin5xwH+QIhMLOScpX91e/NSGPsAzNCvLQDIEPyO2TXi+lBmU6hjLIhV8MwP2kw==} hast-util-from-html@2.0.3: resolution: {integrity: sha512-CUSRHXyKjzHov8yKsQjGOElXy/3EKpyX56ELnkHH34vDVw1N1XSQ1ZcAvTyAPtGqLTuKP/uxM+aLkSPqF/EtMw==} @@ -3872,30 +5052,15 @@ packages: hast-util-from-parse5@8.0.3: resolution: {integrity: sha512-3kxEVkEKt0zvcZ3hCRYI8rqrgwtlIOFMWkbclACvjlDw8Li9S2hk/d51OI0nr/gIpdMHNepwgOKqZ/sy0Clpyg==} - hast-util-has-property@3.0.0: - resolution: {integrity: sha512-MNilsvEKLFpV604hwfhVStK0usFY/QmM5zX16bo7EjnAEGofr5YyI37kzopBlZJkHD4t887i+q/C8/tr5Q94cA==} - - hast-util-is-body-ok-link@3.0.1: - resolution: {integrity: sha512-0qpnzOBLztXHbHQenVB8uNuxTnm/QBFUOmdOSsEn7GnBtyY07+ENTWVFBAnXd/zEgd9/SUG3lRY7hSIBWRgGpQ==} - hast-util-is-element@3.0.0: resolution: {integrity: sha512-Val9mnv2IWpLbNPqc/pUem+a7Ipj2aHacCwgNfTiK0vJKl0LF+4Ba4+v1oPHFpf3bLYmreq0/l3Gud9S5OH42g==} - hast-util-minify-whitespace@1.0.1: - resolution: {integrity: sha512-L96fPOVpnclQE0xzdWb/D12VT5FabA7SnZOUMtL1DbXmYiHJMXZvFkIZfiMmTCNJHUeO2K9UYNXoVyfz+QHuOw==} - hast-util-parse-selector@4.0.0: resolution: {integrity: sha512-wkQCkSYoOGCRKERFWcxMVMOcYE2K1AaNLU8DXS9arxnLOUEWbOXKXiJUNzEpqZ3JOKpnha3jkFrumEjVliDe7A==} - hast-util-phrasing@3.0.1: - resolution: {integrity: sha512-6h60VfI3uBQUxHqTyMymMZnEbNl1XmEGtOxxKYL7stY2o601COo62AWAYBQR9lZbYXYSBoxag8UpPRXK+9fqSQ==} - hast-util-raw@9.1.0: resolution: {integrity: sha512-Y8/SBAHkZGoNkpzqqfCldijcuUKh7/su31kEBp67cFY09Wy0mTRgtsLYsiIxMJxlu0f6AA5SUTbDR8K0rxnbUw==} - hast-util-select@6.0.4: - resolution: {integrity: sha512-RqGS1ZgI0MwxLaKLDxjprynNzINEkRHY2i8ln4DDjgv9ZhcYVIHN9rlpiYsqtFwrgpYU361SyWDQcGNIBVu3lw==} - hast-util-to-estree@3.1.3: resolution: {integrity: sha512-48+B/rJWAp0jamNbAAf9M7Uf//UVqAoMmgXhBdxTDJLGKY+LRnZ99qcG+Qjl5HfMpYNzS5v4EAwVEF34LeAj7w==} @@ -3908,9 +5073,6 @@ packages: hast-util-to-parse5@8.0.1: resolution: {integrity: sha512-MlWT6Pjt4CG9lFCjiz4BH7l9wmrMkfkJYCxFwKQic8+RTZgWPuWxwAfjJElsXkex7DJjfSJsQIt931ilUgmwdA==} - hast-util-to-string@3.0.1: - resolution: {integrity: sha512-XelQVTDWvqcl3axRfI0xSeoVKzyIFPwsAGSLIsKdJKQMXDYJS4WYrBNF/8J7RdhIcFI2BOHgAifggsvsxp/3+A==} - hast-util-to-text@4.0.2: resolution: {integrity: sha512-KK6y/BN8lbaq654j7JgBydev7wuNMcID54lkRav1P0CaE1e47P72AWWPiGKXTJU271ooYzcvTAn/Zt0REnvc7A==} @@ -3926,6 +5088,9 @@ packages: hmac-drbg@1.0.1: resolution: {integrity: sha512-Tti3gMqLdZfhOQY1Mzf/AanLiqh1WTiJgEj26ZuYQ9fbkLomzGchCws4FyrSd4VkpBfiNhaE1On+lOz894jvXg==} + hoist-non-react-statics@3.3.2: + resolution: {integrity: sha512-/gGivxi8JPKWNm/W0jSmzcMPpfpPLc3dY/6GxhX2hQ9iGj3aDfklV4ET7NjKpSinLpJ5vafa9iiGIEZg10SfBw==} + hono@4.12.27: resolution: {integrity: sha512-1yrb/+w6HWQJrUCLkJ2IF5jNIPvvFkblV5RNOYl6bV+OA6p9GLcMpHFFGTosSvHvcAUibuUukRqhlYI4z32C7Q==} engines: {node: '>=16.9.0'} @@ -3937,12 +5102,12 @@ packages: html-escaper@3.0.3: resolution: {integrity: sha512-RuMffC89BOWQoY0WKGpIhn5gX3iI54O6nRA0yC124NYVtzjmFWBIiFd8M0x+ZdX0P9R4lADg1mgP8C7PxGOWuQ==} + html-url-attributes@3.0.1: + resolution: {integrity: sha512-ol6UPyBWqsrO6EJySPz2O7ZSr856WDrEzM5zMqp+FJJLGMW35cLYmmZnl0vztAZxRUoNZJFTCohfjuIJ8I4QBQ==} + html-void-elements@3.0.0: resolution: {integrity: sha512-bEqo66MRXsUGxWHV5IP0PUiAWwoEjba4VCzg0LjFJBpchPaTfyfCKTG6bc5F8ucKec3q5y6qOdGyYTSBEvhCrg==} - html-whitespace-sensitive-tag-names@3.0.1: - resolution: {integrity: sha512-q+310vW8zmymYHALr1da4HyXUQ0zgiIwIicEfotYPWGN0OJVEN/58IJ3A4GBYcEq3LGAZqKb+ugvP0GNB9CEAA==} - http-cache-semantics@4.2.0: resolution: {integrity: sha512-dTxcvPXqPvXBQpq5dUr6mEMJX4oIEFv6bwom3FDwKRDsuIjjJGANqhBuoAn9c1RQJIdAKav33ED65E2ys+87QQ==} @@ -3957,6 +5122,10 @@ packages: https-browserify@1.0.0: resolution: {integrity: sha512-J+FkSdyD+0mA0N+81tMotaRMfSL9SGi+xpD3T6YApKsc3bGSXJlfXri3VyFOeYkfLRQisDk1W+jIFFKBeUBbBg==} + https-proxy-agent@5.0.1: + resolution: {integrity: sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA==} + engines: {node: '>= 6'} + https-proxy-agent@7.0.6: resolution: {integrity: sha512-vK9P5/iUfdl95AI+JVyUuIcVtd4ofvtrOr3HNtM2yxC9bnMbEdp3x01OhQNnjb8IJYi38VlTE3mBXwcfvywuSw==} engines: {node: '>= 14'} @@ -3965,8 +5134,9 @@ packages: resolution: {integrity: sha512-AXcZb6vzzrFAUE61HnN4mpLqd/cSIwNQjtNWR0euPm6y0iqx3G4gOXaIDdtdDwZmhwe82LA6+zinmW4UBWVePQ==} engines: {node: '>=16.17.0'} - i18next@23.16.8: - resolution: {integrity: sha512-06r/TitrM88Mg5FdUXAKL96dJMzgqLE5dv3ryBAra4KCwD9mJ4ndOTS95ZuymIGoE+2hzfdaMak2X11/es7ZWg==} + iconv-lite@0.6.3: + resolution: {integrity: sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==} + engines: {node: '>=0.10.0'} iconv-lite@0.7.2: resolution: {integrity: sha512-im9DjEDQ55s9fL4EYzOAv0yMqmMBSZp6G0VvFyTMPKWxiSBHUj9NW/qqLmXUwXrrM7AvqSlTCfvqRb0cM8yYqw==} @@ -3988,6 +5158,19 @@ packages: inline-style-parser@0.2.7: resolution: {integrity: sha512-Nb2ctOyNR8DqQoR0OwRG95uNWIC0C1lCgf5Naz5H6Ji72KZ8OcFZLz2P5sNgwlyoJ8Yif11oMuYs5pBQa86csA==} + input-otp@1.4.2: + resolution: {integrity: sha512-l3jWwYNvrEa6NTCt7BECfCm48GvwuZzkoeG3gBL2w4CHeOXW3eKFmf9UNYkNfYc3mxMrthMnxjIE07MT0zLBQA==} + peerDependencies: + react: ^16.8 || ^17.0 || ^18.0 || ^19.0.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0.0 || ^19.0.0-rc + + internmap@1.0.1: + resolution: {integrity: sha512-lDB5YccMydFBtasVtxnZ3MRBHuaoE8GKsppq+EchKL2U4nK/DmEpPHNH8MZe5HkMtpSiTSOZwfN0tzYjO/lJEw==} + + internmap@2.0.3: + resolution: {integrity: sha512-5Hh7Y1wQbvY5ooGgPbDaL5iYLAPzMTUrjMulskHLH6wnv/A+1q5rgEaiuqEjB+oxGXIVZs1FF+R/KPN3ZSQYYg==} + engines: {node: '>=12'} + ip-address@10.2.0: resolution: {integrity: sha512-/+S6j4E9AHvW9SWMSEY9Xfy66O5PWvVEJ08O0y5JGyEKQpojb0K0GKpz/v5HJ/G0vi3D2sjGK78119oXZeE0qA==} engines: {node: '>= 12'} @@ -4110,6 +5293,30 @@ packages: jose@6.2.3: resolution: {integrity: sha512-YYVDInQKFJfR/xa3ojUTl8c2KoTwiL1R5Wg9YCydwH0x0B9grbzlg5HC7mMjCtUJjbQ/YnGEZIhI5tCgfTb4Hw==} + jotai-effect@2.3.1: + resolution: {integrity: sha512-FBBVXDM2podbbxJsZ19+uDv45LxeXoVA5yh6CfkQ35AVCuRHj7Lanlcjiea3b67Q7+/MMGXWf8+GeB73JcbeMg==} + engines: {node: '>=12.20.0'} + peerDependencies: + jotai: '>=2.20.0' + + jotai@2.20.1: + resolution: {integrity: sha512-dnuKfU/GLi8B28RRMjQ3AfoN7kfzP8o41+AX2FmITZqEMY8PHnjABq+VkEooomLwYaGjda+pgy0yFSjaHX/ZPg==} + engines: {node: '>=12.20.0'} + peerDependencies: + '@babel/core': '>=7.0.0' + '@babel/template': '>=7.0.0' + '@types/react': '>=17.0.0' + react: '>=17.0.0' + peerDependenciesMeta: + '@babel/core': + optional: true + '@babel/template': + optional: true + '@types/react': + optional: true + react: + optional: true + js-tokens@4.0.0: resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==} @@ -4146,17 +5353,26 @@ packages: jws@4.0.1: resolution: {integrity: sha512-EKI/M/yqPncGUUh44xz0PxSidXFr/+r0pA70+gIYhjv+et7yxM+s29Y+VGDkovRofQem0fs7Uvf4+YmAdyRduA==} + katex@0.16.47: + resolution: {integrity: sha512-Eeo8Ys1doU1z+x8AZsPpQu+p/QcZBI5PeOo7QGQdy2x2m0MU/hYagBbGOmXwr5KVbEfVuWv9LpnQWeehogurjg==} + hasBin: true + + khroma@2.1.0: + resolution: {integrity: sha512-Ls993zuzfayK269Svk9hzpeGUKob/sIgZzyHYdjQoAdQetRKpOLj+k/QQQ/6Qi0Yz65mlROrfd+Ev+1+7dz9Kw==} + kleur@3.0.3: resolution: {integrity: sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w==} engines: {node: '>=6'} - klona@2.0.6: - resolution: {integrity: sha512-dhG34DXATL5hSxJbIexCft8FChFXtmskoZYnoPWjXQuebWYCNkVeV3KkGegCK9CP1oswI/vQibS2GY7Em/sJJA==} - engines: {node: '>= 8'} - koffi@2.16.2: resolution: {integrity: sha512-owU0MRwv6xkrVqCd+33uw6BaYppkTRXbO/rVdJNI2dvZG0gzyRhYwW25eWtc5pauwK8TGh3AbkFONSezdykfSA==} + layout-base@1.0.2: + resolution: {integrity: sha512-8h2oVEZNktL4BH2JCOI90iD1yXwL6iNW7KcCKT2QZgQJR2vbqDsldCTPRU9NifTCqHZci57XvQQ15YTu+sTYPg==} + + layout-base@2.0.1: + resolution: {integrity: sha512-dp3s92+uNI1hWIpPGH3jK2kxE2lMjdXdr+DH8ynZHpd6PUlH6x6cbuXnoMmiNumznqaNO31xu9e79F0uuZ0JFg==} + lilconfig@3.1.3: resolution: {integrity: sha512-/vlFKAoH5Cgt3Ie+JLhRbwOsCQePABiU3tJ1egGvyQ+33R/vcwM2Zl2QR/LzjsBeItPt3oSVXapn+m4nQDvpzw==} engines: {node: '>=14'} @@ -4171,15 +5387,32 @@ packages: resolution: {integrity: sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==} engines: {node: '>=10'} + lodash-es@4.18.1: + resolution: {integrity: sha512-J8xewKD/Gk22OZbhpOVSwcs60zhd95ESDwezOFuA3/099925PdHJ7OFHNTGtajL3AlZkykD32HykiMo+BIBI8A==} + lodash.camelcase@4.3.0: resolution: {integrity: sha512-TwuEnCnxbc3rAvhf/LbG7tJUDzhqXyFnv3dtzLOPgCG/hODL7WFnsbwktkD7yUV0RrreP/l1PALq/YSg6VvjlA==} + lodash.debounce@4.0.8: + resolution: {integrity: sha512-FT1yDzDYEoYWhnSGnpE/4Kj1fLZkDFyqRb7fNt6FdYOSxlUWAtp42Eh6Wb0rGIv/m9Bgo7x4GhQbm5Ys4SG5ow==} + + lodash@4.18.1: + resolution: {integrity: sha512-dMInicTPVE8d1e5otfwmmjlxkZoUpiVLwyeTdUsi/Caj/gfzzblBcCE5sRHV/AsjuCmxWrte2TNGSYuCeCq+0Q==} + + loglevel@1.9.2: + resolution: {integrity: sha512-HgMmCqIJSAKqo68l0rS2AanEWfkxaZ5wNiEFb5ggm08lDs9Xl2KxBlX3PTcaD2chBM1gXAYf491/M2Rv8Jwayg==} + engines: {node: '>= 0.6.0'} + long@5.3.2: resolution: {integrity: sha512-mNAgZ1GmyNhD7AuqnTG3/VQ26o760+ZYBPKjPvugO8+nLbYfX6TVpJPseBvopbdY+qpZ/lKUnmEc1LeZYS3QAA==} longest-streak@3.1.0: resolution: {integrity: sha512-9Ri+o0JYgehTaVBBDoMqIl8GXtbWg711O3srftcHhZ0dqnETqLaoIK0x17fUw9rFSlK/0NlsKe0Ahhyl5pXE2g==} + loose-envify@1.4.0: + resolution: {integrity: sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==} + hasBin: true + loupe@3.2.1: resolution: {integrity: sha512-CdzqowRJCeLU72bHvWqwRBBlLcMEtIvGrlvef74kMnV2AolS9Y8xUv1I0U/MNAWMhBlKIoyuEgoJ0t/bbwHbLQ==} @@ -4197,6 +5430,11 @@ packages: resolution: {integrity: sha512-jumlc0BIUrS3qJGgIkWZsyfAM7NCWiBcCDhnd+3NNM5KbBmLTgHVfWBcg6W+rLUsIpzpERPsvwUP7CckAQSOoA==} engines: {node: '>=12'} + lucide-react@0.439.0: + resolution: {integrity: sha512-PafSWvDTpxdtNEndS2HIHxcNAbd54OaqSYJO90/b63rab2HWYqDbH194j0i82ZFdWOAcf0AHinRykXRRK2PJbw==} + peerDependencies: + react: ^16.5.1 || ^17.0.0 || ^18.0.0 || ^19.0.0-rc + lucide-react@0.469.0: resolution: {integrity: sha512-28vvUnnKQ/dBwiCQtwJw7QauYnE7yd2Cyp4tTTJpvglX4EMpbflcdBgrgToX2j71B3YvugK/NH3BGUk+E/p/Fw==} peerDependencies: @@ -4227,6 +5465,11 @@ packages: engines: {node: '>= 18'} hasBin: true + marked@16.4.2: + resolution: {integrity: sha512-TI3V8YYWvkVf3KJe1dRkpnjs68JUPyEa5vjKrp1XEEJUAOaQc+Qj+L1qWbPd0SJuAdQkFU0h73sXXqwDYxsiDA==} + engines: {node: '>= 20'} + hasBin: true + math-intrinsics@1.1.0: resolution: {integrity: sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==} engines: {node: '>= 0.4'} @@ -4237,9 +5480,6 @@ packages: mdast-util-definitions@6.0.0: resolution: {integrity: sha512-scTllyX6pnYNZH/AIp/0ePz6s4cZtARxImwoPJ7kS42n+MnVsI4XbnG6d4ibehRIldYMWM2LD7ImQblVhUejVQ==} - mdast-util-directive@3.1.0: - resolution: {integrity: sha512-I3fNFt+DHmpWCYAT7quoM6lHf9wuqtI+oCOfvILnoicNIqjh5E3dEJWiXuYME2gNe8vl1iMQwyUHa7bgFmak6Q==} - mdast-util-find-and-replace@3.0.2: resolution: {integrity: sha512-Tmd1Vg/m3Xz43afeNxDIhWRtFZgM2VLyaf4vSTYwudTyeuTneoL3qtWMA5jeLyz/O1vDJmmV4QuScFCA2tBPwg==} @@ -4297,6 +5537,9 @@ packages: mdurl@2.0.0: resolution: {integrity: sha512-Lf+9+2r+Tdp5wXDXC4PcIBjTDtq4UKjCPMQhKIuzpJNW0b96kVqSwW0bT7FhRSfmAiFYgP+SCRvdrDozfh0U5w==} + mdx-annotations@0.1.4: + resolution: {integrity: sha512-SUYBUXP1qbgr0nRFFnUBg4HxxTbYyl5rE38fLTaIm0naPK+EhmKa0wRlUdgTMlMBj5gdCMwP1n7+L47JIHHWUQ==} + media-typer@1.1.0: resolution: {integrity: sha512-aisnrDP4GNe06UcKFnV5bfMNPBUw4jsLGaWwWfnH3v02GnBuXX2MCVn5RbrWo0j3pczUilYblq7fQ7Nw2t5XKw==} engines: {node: '>= 0.8'} @@ -4312,12 +5555,20 @@ packages: resolution: {integrity: sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==} engines: {node: '>= 8'} + mermaid-isomorphic@3.1.0: + resolution: {integrity: sha512-mzrvfEVjnJIkJlEqxp3eMuR1wS0TeLCH1VK5E/T5yzWaBwI3JqjJuw70yUIThSCDJ5bRs6O3rgfp00oBAbvSeQ==} + peerDependencies: + playwright: '1' + peerDependenciesMeta: + playwright: + optional: true + + mermaid@11.16.0: + resolution: {integrity: sha512-Zvm3kbstgdpvIJPPItlL7fppIZ3kibvc1oZIGxdvk9t6UFz6flv+Jw7FtRGKwfcI8OckmH04LqG6LlS6X4B1pA==} + micromark-core-commonmark@2.0.3: resolution: {integrity: sha512-RDBrHEMSxVFLg6xvnXmb1Ayr2WzLAWjeSATAoxwKYJV94TeNavgoIdA0a9ytzDSVzBy2YKFK+emCPOEibLeCrg==} - micromark-extension-directive@3.0.2: - resolution: {integrity: sha512-wjcXHgk+PPdmvR58Le9d7zQYWy+vKEU9Se44p2CrCDPiLr2FMyiT4Fyb5UFKFC66wGB3kPlgD7q3TnoqPS7SZA==} - micromark-extension-gfm-autolink-literal@2.1.0: resolution: {integrity: sha512-oOg7knzhicgQ3t4QCjCWgTmfNhvQbDDnJeVu9v81r7NltNCVmhPy1fJRX27pISafdjL+SVc4d3l48Gb6pbRypw==} @@ -4428,10 +5679,18 @@ packages: resolution: {integrity: sha512-115fLhvZVqWwHPbClyntxEVfVDfl9DLLTuJvq3g2O/Oxi8AiNouAHvDSzHS0viUJc+V5vm3eq91Xwqn9dp4jRA==} hasBin: true + mime-db@1.52.0: + resolution: {integrity: sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==} + engines: {node: '>= 0.6'} + mime-db@1.54.0: resolution: {integrity: sha512-aU5EJuIN2WDemCcAp2vFBfp/m4EAhWJnUNSSw0ixs7/kXbd6Pg64EmwJkNdFhB8aWt1sH2CTXrLxo/iAGV3oPQ==} engines: {node: '>= 0.6'} + mime-types@2.1.35: + resolution: {integrity: sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==} + engines: {node: '>= 0.6'} + mime-types@3.0.2: resolution: {integrity: sha512-Lbgzdk0h4juoQ9fCKXW4by0UJqj+nOOrI9MJ1sSj4nI8aI2eo1qmvQEie4VD1glsS250n15LsWsYtCugiStS5A==} engines: {node: '>=18'} @@ -4440,6 +5699,10 @@ packages: resolution: {integrity: sha512-vqiC06CuhBTUdZH+RYl8sFrL096vA45Ok5ISO6sE/Mr1jRbGH4Csnhi8f3wKVl7x8mO4Au7Ir9D3Oyv1VYMFJw==} engines: {node: '>=12'} + mini-svg-data-uri@1.4.4: + resolution: {integrity: sha512-r9deDe9p5FJUPZAk3A59wGH7Ii9YrjjWw0jmw/liSbHl2CHiyXj6FcDXDu2K3TjVAXqiJdaw3xxwlZZr9E6nHg==} + hasBin: true + minimalistic-assert@1.0.1: resolution: {integrity: sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A==} @@ -4461,9 +5724,15 @@ packages: mkdirp-classic@0.5.3: resolution: {integrity: sha512-gKLcREMhtuZRwRAfqP3RFW+TK4JqApVBtOIftVgjuABpAtpxhPGaDcfvbhNvD0B8iD1oUr/txX35NjcaY6Ns/A==} + motion-dom@11.18.1: + resolution: {integrity: sha512-g76KvA001z+atjfxczdRtw/RXOM3OMSdd1f4DL77qCTF/+avrRJiawSG4yDibEQ215sr9kpinSlX2pCTJ9zbhw==} + motion-dom@12.40.0: resolution: {integrity: sha512-HxU3ZaBwNPVQUBQf1xxgq+7JrPNZvjLVxgbpEZL7RrWJnsxOf0/OM+yrHG9ogLQ31Do/r57Oz2gQWPK+6q62mg==} + motion-utils@11.18.1: + resolution: {integrity: sha512-49Kt+HKjtbJKLtgO/LKj9Ld+6vw9BjH5d9sc40R/kVyH8GLAXgT42M2NnuPcJNuA3s9ZfZBUcwIgpmZWGEE+hA==} + motion-utils@12.39.0: resolution: {integrity: sha512-8nadJAJjTtqRkmRF36FoJTrywK9nnFmnPwnSMyxaOCU7GDjN9RTMJIxx9De8ErM+vpPhMccr/6fo5WciyQLnMQ==} @@ -4634,10 +5903,6 @@ packages: package-manager-detector@1.6.0: resolution: {integrity: sha512-61A5ThoTiDG/C8s8UMZwSorAGwMJ0ERVGj2OjoW5pAalsNOg15+iQiPzrLJ4jhZ1HJzmC2PIHT2oEiH3R5fzNA==} - pagefind@1.5.2: - resolution: {integrity: sha512-XTUaK0hXMCu2jszWE584JGQT7y284TmMV9l/HX3rnG5uo3rHI/uHU56XTyyyPFjeWEBxECbAi0CaFDJOONtG0Q==} - hasBin: true - pako@1.0.11: resolution: {integrity: sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw==} @@ -4673,6 +5938,9 @@ packages: path-browserify@1.0.1: resolution: {integrity: sha512-b7uo2UCUOYZcnF/3ID0lulOJi/bafxa1xPe7ZPsammBSpjSWQkjNxlt635YGS2MiR9GjvuXCtz2emr3jbsz98g==} + path-data-parser@0.1.0: + resolution: {integrity: sha512-NOnmBpt5Y2RWbuv0LMzsayp3lVylAHLPUTut412ZA3l+C4uw4ZVkQbjShYCQ8TCpUMdPapr4YjUqLYD6v68j+w==} + path-exists@4.0.0: resolution: {integrity: sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==} engines: {node: '>=8'} @@ -4766,6 +6034,12 @@ packages: resolution: {integrity: sha512-LKWqWJRhstyYo9pGvgor/ivk2w94eSjE3RGVuzLGlr3NmD8bf7RcYGze1mNdEHRP6TRP6rMuDHk5t44hnTRyow==} engines: {node: '>=14.19.0'} + points-on-curve@0.2.0: + resolution: {integrity: sha512-0mYKnYYe9ZcqMCWhUjItv/oHjvgEsfKvnUTg8sAtnHr3GVy7rGkXCb6d5cSyqrWqL4k81b9CPg3urd+T7aop3A==} + + points-on-path@0.2.1: + resolution: {integrity: sha512-25ClnWWuw7JbWZcgqY/gJ4FQWadKxGWk+3kR/7kD0tCaDtPPMj7oHu2ToLaVhfpnHrZzYby2w6tUA0eOIuUg8g==} + possible-typed-array-names@1.1.0: resolution: {integrity: sha512-/+5VFTchJDoVj3bhoqi6UeymcD00DAwb1nJwamzPvHEszJ4FpF6SNNbUbOS8yI56qHzdV8eK0qEfOSiodkTdxg==} engines: {node: '>= 0.4'} @@ -4818,6 +6092,10 @@ packages: peerDependencies: postcss: ^8.2.14 + postcss-selector-parser@6.0.10: + resolution: {integrity: sha512-IQ7TZdoaqbT+LCpShg46jnZVlhWD2w6iQYAcYXfHARZ7X1t/UGhhceQDs5X0cGqKvYlHNOuv7Oa1xmb0oQuA3w==} + engines: {node: '>=4'} + postcss-selector-parser@6.1.4: resolution: {integrity: sha512-bIoJLOmjCO1S9XdY/DcnR5hJxvrDir1PbGChrzXG3vw0/FOliy/fA3dmdhQ441kah4gKv+TwckGzex6wNS5cnQ==} engines: {node: '>=4'} @@ -4829,6 +6107,12 @@ packages: resolution: {integrity: sha512-OW/rX8O/jXnm82Ey1k44pObPtdblfiuWnrd8X7GJ7emImCOstunGbXUpp7HdBrFQX6rJzn3sPT397Wp5aCwCHg==} engines: {node: ^10 || ^12 || >=14} + posthog-js@1.395.0: + resolution: {integrity: sha512-5iTb00CGt2eQUUiBQysQiX89RAbCN6wK2sDNzvs9zv0alaY8mJ0ZySrUD3LQ+XyLhgM5pCpacBuUwChqiYDLDw==} + + preact@10.29.3: + resolution: {integrity: sha512-D9NL1GAnJZhc3RndVs4gDdxEeU9TcHgywMrhhOsnpdlvFjdbx0gAsLUnH6JEhlJH5giL7Tx5biWPUSEXE/HPzw==} + prismjs@1.30.0: resolution: {integrity: sha512-DEvV2ZF2r2/63V+tK8hQvrR2ZGn10srHbXviTlcv7Kpzw8jWiNTqbVgjO3IY8RxrrOUF8VPMQQFysYYYv0YZxw==} engines: {node: '>=6'} @@ -4844,6 +6128,9 @@ packages: resolution: {integrity: sha512-NxNv/kLguCA7p3jE8oL2aEBsrJWgAakBpgmgK6lpPWV+WuOmY6r2/zbAVnP+T8bQlA0nzHXSJSJW0Hq7ylaD2Q==} engines: {node: '>= 6'} + prop-types@15.8.1: + resolution: {integrity: sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==} + proper-lockfile@4.1.2: resolution: {integrity: sha512-TjNPblN4BwAWMXU8s9AEz4JmQxnD1NNL7bNOY/AKUzyamc379FWASUhc/K1pL2noVb+XmZKLL68cjzLsiOAMaA==} @@ -4865,6 +6152,10 @@ packages: proxy-from-env@1.1.0: resolution: {integrity: sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==} + proxy-from-env@2.1.0: + resolution: {integrity: sha512-cJ+oHTW1VAEa8cJslgmUZrc+sjRKgAKl3Zyse6+PV38hZe/V6Z14TbCuXcan9F9ghlz4QrFr2c92TNF82UkYHA==} + engines: {node: '>=10'} + public-encrypt@4.0.3: resolution: {integrity: sha512-zVpa8oKZSz5bTMTFClc1fQOnyyEzpl5ozpi1B5YcvBrdohMjH2rfsBtyXcuNuwjsDIXmBYlF2N5FlJYhR29t8Q==} @@ -4886,6 +6177,9 @@ packages: resolution: {integrity: sha512-O9gl3zCl5h5blw1KGUzQKhA5oUXSl8rwUIM5o0S3nCXMliSvy5Dzx7/DJcI+SwgICv+IneSZwhBh1oSyEHA71A==} engines: {node: '>=0.6'} + query-selector-shadow-dom@1.0.1: + resolution: {integrity: sha512-lT5yCqEBgfoMYpf3F2xQRK7zEr1rhIIZuceDK6+xRkJQ4NMbHTwXqk4NkwDwQMNqXgG9r9fyHnzwNVs6zV5KRw==} + querystring-es3@0.2.1: resolution: {integrity: sha512-773xhDQnZBMFobEiztv8LIl70ch5MSF/jUQVlhwFyBILqq96anmoctVIYz+ZRp0qbCKATTn6ev02M3r7Ga5vqA==} engines: {node: '>=0.4.x'} @@ -4910,15 +6204,98 @@ packages: resolution: {integrity: sha512-K5zQjDllxWkf7Z5xJdV0/B0WTNqx6vxG70zJE4N0kBs4LovmEYWJzQGxC9bS9RAKu3bgM40lrd5zoLJ12MQ5BA==} engines: {node: '>= 0.10'} + react-aria@3.50.0: + resolution: {integrity: sha512-S0Os6QZk33fzUAKu1QLT9afoUaCBt1ZNdoiq0n2YMVgKIdNIQS8zxiZ8O9hYE6QyDkHKjD6q39LQZ+qaSAIgjw==} + peerDependencies: + react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1 + react-dom: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1 + + react-day-picker@8.10.1: + resolution: {integrity: sha512-TMx7fNbhLk15eqcMt+7Z7S2KF7mfTId/XJDjKE8f+IUcFn0l08/kI4FiYTL/0yuOLmEcbR4Fwe3GJf/NiiMnPA==} + peerDependencies: + date-fns: ^2.28.0 || ^3.0.0 + react: ^16.8.0 || ^17.0.0 || ^18.0.0 + react-dom@19.2.7: resolution: {integrity: sha512-t0BRVXvbiE/o20Hfw669rLbMCDWtYZLvmJigy2f0MxsXF+71pxhR3xOkspmsO8h3ZlNzyibAmtCa3l4lYKk6gQ==} peerDependencies: react: ^19.2.7 + react-hook-form@7.80.0: + resolution: {integrity: sha512-4P+fk6oXsxY+6xSj7Euhc2sumQD8zQqCuVHoJwoyp9EchP+IUW9OESB7uHFJOKsIBQ4MQqYE84INJFqUCYNoOg==} + engines: {node: '>=18.0.0'} + peerDependencies: + react: ^16.8.0 || ^17 || ^18 || ^19 + + react-is@16.13.1: + resolution: {integrity: sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==} + + react-is@18.3.1: + resolution: {integrity: sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg==} + + react-markdown@10.1.0: + resolution: {integrity: sha512-qKxVopLT/TyA6BX3Ue5NwabOsAzm0Q7kAPwq6L+wWDwisYs7R8vZ0nRXqq6rkueboxpkjvLGU9fWifiX/ZZFxQ==} + peerDependencies: + '@types/react': '>=18' + react: '>=18' + react-refresh@0.17.0: resolution: {integrity: sha512-z6F7K9bV85EfseRCp2bzrpyQ0Gkw1uLoCel9XBVWPg/TjRj94SkJzUTGfOa4bs7iJvBWtQG0Wq7wnI0syw3EBQ==} engines: {node: '>=0.10.0'} + react-remove-scroll-bar@2.3.8: + resolution: {integrity: sha512-9r+yi9+mgU33AKcj6IbT9oRCO78WriSj6t/cF8DWBZJ9aOGPOTEDvdUDz1FwKim7QXWwmHqtdHnRJfhAxEG46Q==} + engines: {node: '>=10'} + peerDependencies: + '@types/react': '*' + react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 + peerDependenciesMeta: + '@types/react': + optional: true + + react-remove-scroll@2.7.2: + resolution: {integrity: sha512-Iqb9NjCCTt6Hf+vOdNIZGdTiH1QSqr27H/Ek9sv/a97gfueI/5h1s3yRi1nngzMUaOOToin5dI1dXKdXiF+u0Q==} + engines: {node: '>=10'} + peerDependencies: + '@types/react': '*' + react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + + react-resizable-panels@2.1.9: + resolution: {integrity: sha512-z77+X08YDIrgAes4jl8xhnUu1LNIRp4+E7cv4xHmLOxxUPO/ML7PSrE813b90vj7xvQ1lcf7g2uA9GeMZonjhQ==} + peerDependencies: + react: ^16.14.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc + react-dom: ^16.14.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc + + react-smooth@4.0.4: + resolution: {integrity: sha512-gnGKTpYwqL0Iii09gHobNolvX4Kiq4PKx6eWBCYYix+8cdw+cGo3do906l1NBPKkSWx1DghC1dlWG9L2uGd61Q==} + peerDependencies: + react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 + react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 + + react-stately@3.48.0: + resolution: {integrity: sha512-ImicSAG+lTotAe5izcs1fz49Zk48w7pDusqYg04WaPhCoej8BJ24soMu3iLXIrsi273s4P1gZrYGrqReMfgEEA==} + peerDependencies: + react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1 + + react-style-singleton@2.2.3: + resolution: {integrity: sha512-b6jSvxvVnyptAiLjbkWLE/lOnR4lfTtDAl+eUC7RZy+QQWc6wRzIV2CE6xBuMmDxc2qIihtDCZD5NPOFl7fRBQ==} + engines: {node: '>=10'} + peerDependencies: + '@types/react': '*' + react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + + react-transition-group@4.4.5: + resolution: {integrity: sha512-pZcd1MCJoiKiBR2NRxeCRg13uCXbydPnmB4EOeRrY7480qNWO8IIgQG6zlDkm6uRMsURXPuKq0GWtiM59a5Q6g==} + peerDependencies: + react: '>=16.6.0' + react-dom: '>=16.6.0' + react@19.2.7: resolution: {integrity: sha512-HNe9WslTbXmFK8o8cmwgAeJFSBvt1bPdHCVKtaaV+WlAN36mpT4hcRpwbf3fY56ar2oIXzsBpOAiIRHAdY0OlQ==} engines: {node: '>=0.10.0'} @@ -4941,6 +6318,17 @@ packages: resolution: {integrity: sha512-9u/XQ1pvrQtYyMpZe7DXKv2p5CNvyVwzUB6uhLAnQwHMSgKMBR62lc7AHljaeteeHXn11XTAaLLUVZYVZyuRBQ==} engines: {node: '>= 20.19.0'} + recharts-scale@0.4.5: + resolution: {integrity: sha512-kivNFO+0OcUNu7jQquLXAxz1FIwZj8nrj+YkOKc5694NbjCvcT6aSZiIzNzd2Kul4o4rTto8QVR9lMNtxD4G1w==} + + recharts@2.15.4: + resolution: {integrity: sha512-UT/q6fwS3c1dHbXv2uFgYJ9BMFHu3fwnd7AYZaEQhXuYQ4hgsxLvsUXzGdKeZrW5xopzDCvuA2N41WJ88I7zIw==} + engines: {node: '>=14'} + deprecated: 1.x and 2.x branches are no longer active. Bump to Recharts v3 to receive latest features and bugfixes. See https://github.com/recharts/recharts/wiki/3.0-migration-guide + peerDependencies: + react: ^16.0.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 + react-dom: ^16.0.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 + recma-build-jsx@1.0.0: resolution: {integrity: sha512-8GtdyqaBcDfva+GUKDr3nev3VpKAhup1+RvkMvUxURHpW7QyIvk9F5wz7Vzo06CEMSilw6uArgRqhpiUcWp8ew==} @@ -4964,11 +6352,13 @@ packages: regex@6.1.0: resolution: {integrity: sha512-6VwtthbV4o/7+OaAF9I5L5V3llLEsoPyq9P1JVXkedTP33c7MfCG0/5NOPcSJn0TzXcG9YUrR0gQSWioew3LDg==} - rehype-expressive-code@0.41.7: - resolution: {integrity: sha512-25f8ZMSF1d9CMscX7Cft0TSQIqdwjce2gDOvQ+d/w0FovsMwrSt3ODP4P3Z7wO1jsIJ4eYyaDRnIR/27bd/EMQ==} - - rehype-format@5.0.1: - resolution: {integrity: sha512-zvmVru9uB0josBVpr946OR8ui7nJEdzZobwLOOqHb/OOD88W0Vk2SqLwoVOj0fM6IPCCO6TaV9CvQvJMWwukFQ==} + rehype-mermaid@3.0.0: + resolution: {integrity: sha512-fxrD5E4Fa1WXUjmjNDvLOMT4XB1WaxcfycFIWiYU0yEMQhcTDElc9aDFnbDFRLxG1Cfo1I3mfD5kg4sjlWaB+Q==} + peerDependencies: + playwright: '1' + peerDependenciesMeta: + playwright: + optional: true rehype-parse@9.0.1: resolution: {integrity: sha512-ksCzCD0Fgfh7trPDxr2rSylbwq9iYDkSn8TCDmEJ49ljEUBxDVCzCHv7QNzZOfODanX4+bWQ4WZqLCRWYLfhag==} @@ -4985,9 +6375,6 @@ packages: rehype@13.0.2: resolution: {integrity: sha512-j31mdaRFrwFRUIlxGeuPXXKWQxet52RBQRvCmzl5eCefn/KGbomK5GMHNMsOJf55fgo3qw5tST5neDuarDYR2A==} - remark-directive@3.0.1: - resolution: {integrity: sha512-gwglrEQEZcZYgVyG1tQuA+h58EZfq5CSULw7J90AFuCTyib1thgHPoqQ+h9iFvU6R+vnZ5oNFQR5QKgGpk741A==} - remark-gfm@4.0.1: resolution: {integrity: sha512-1quofZ2RQ9EWdeN34S79+KExV1764+wCUGop5CPL1WGdD0ocPpu91lzPGbwWMECpEpd42kJGQwzRfyov9j4yNg==} @@ -5051,11 +6438,17 @@ packages: resolution: {integrity: sha512-5Di9UC0+8h1L6ZD2d7awM7E/T4uA1fJRlx6zk/NvdCCVEoAnFqvHmCuNeIKoCeIixBX/q8uM+6ycDvF8woqosA==} engines: {node: '>= 0.8'} + robust-predicates@3.0.3: + resolution: {integrity: sha512-NS3levdsRIUOmiJ8FZWCP7LG3QpJyrs/TE0Zpf1yvZu8cAJJ6QMW92H1c7kWpdIHo8RvmLxN/o2JXTKHp74lUA==} + rollup@4.60.1: resolution: {integrity: sha512-VmtB2rFU/GroZ4oL8+ZqXgSA38O6GR8KSIvWmEFv63pQ0G6KaBH9s07PO8XTXP4vI+3UJUEypOfjkGfmSBBR0w==} engines: {node: '>=18.0.0', npm: '>=8.0.0'} hasBin: true + roughjs@4.6.6: + resolution: {integrity: sha512-ZUz/69+SYpFN/g/lUlo2FXcIjRkSu3nDarreVdGGndHEBJ6cXPdKguS8JGxwj5HA5xIbVKSmLgr5b3AWxtRfvQ==} + router@2.2.0: resolution: {integrity: sha512-nLTrUKm2UyiL7rlhapu/Zl45FwNgkZGaCpZbIHajDYgwlJCOzLSk+cIPAnsEqV955GjILJnKbdQC1nVPz+gAYQ==} engines: {node: '>= 18'} @@ -5063,6 +6456,9 @@ packages: run-parallel@1.2.0: resolution: {integrity: sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==} + rw@1.3.3: + resolution: {integrity: sha512-PdhdWy89SiZogBLaw42zdeqtRJ//zFd2PgQavcICDUgJT5oW10QCRKbJ6bg4r0/UY2M6BWd5tkxuGFRvCkgfHQ==} + safe-buffer@5.1.2: resolution: {integrity: sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==} @@ -5227,6 +6623,12 @@ packages: resolution: {integrity: sha512-LJhUYUvItdQ0LkJTmPeaEObWXAqFyfmP85x0tch/ez9cahmhlBBLbIqDFnvBnUJGagb0JbIQrkBs1wJ+yRYpEw==} engines: {node: '>= 10.0.0', npm: '>= 3.0.0'} + sonner@1.7.4: + resolution: {integrity: sha512-DIS8z4PfJRbIyfVFDVnK9rO3eYDtse4Omcm6bt0oEr5/jtLgysmjuBl1frJ9E/EQZrFmKx2A8m/s5s9CRXIzhw==} + peerDependencies: + react: ^18.0.0 || ^19.0.0 || ^19.0.0-rc + react-dom: ^18.0.0 || ^19.0.0 || ^19.0.0-rc + source-map-js@1.2.1: resolution: {integrity: sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==} engines: {node: '>=0.10.0'} @@ -5305,12 +6707,18 @@ packages: resolution: {integrity: sha512-ki4hZQfh5rX0QDLLkOCj+h+CVNkqmp/CMf8v8kZpkNVK6jGQooMytqzLZYUVYIZcFZ6yDB70EfD8POcFXiF5oA==} engines: {node: '>=18'} + style-mod@4.1.3: + resolution: {integrity: sha512-i/n8VsZydrugj3Iuzll8+x/00GH2vnYsk1eomD8QiRrSAeW6ItbCQDtfXCeJHd0iwiNagqjQkvpvREEPtW3IoQ==} + style-to-js@1.1.21: resolution: {integrity: sha512-RjQetxJrrUJLQPHbLku6U/ocGtzyjbJMP9lCNK7Ag0CNh690nSH8woqWH9u16nMjYBAok+i7JO1NP2pOy8IsPQ==} style-to-object@1.0.14: resolution: {integrity: sha512-LIN7rULI0jBscWQYaSswptyderlarFkjQ+t79nzty8tcIAceVomEVlLzH5VP4Cmsv6MtKhs7qaAiwlcp+Mgaxw==} + stylis@4.4.0: + resolution: {integrity: sha512-5Z9ZpRzfuH6l/UAvCPAPUo3665Nk2wLaZU3x+TLHKVzIz33+sbJqbtrYoC3KD4/uVOr2Zp+L0LySezP9OHV9yA==} + sucrase@3.35.1: resolution: {integrity: sha512-DhuTmvZWux4H1UOnWMB3sk0sbaCVOoQZjv8u1rDoTV0HTdGem9hkAZtl4JZy8P2z4Bg0nT+YMeOFyVr4zcG5Tw==} engines: {node: '>=16 || 14 >=14.17'} @@ -5329,6 +6737,17 @@ packages: engines: {node: '>=16'} hasBin: true + tabbable@6.5.0: + resolution: {integrity: sha512-wieBHXygIm7OyQOu5hQlkk62/WyCFYGlWg7L6/ZCUZwx0o398Zkn4pVmMyfYhfMG8kGrj/Krt8eIk6UKC6VzwA==} + + tailwind-merge@2.6.1: + resolution: {integrity: sha512-Oo6tHdpZsGpkKG88HJ8RR1rg/RdnEkQEfMoEk2x1XRI3F1AxeU+ijRXpiVUF4UbLfcxxRGw6TbUINKYdWVsQTQ==} + + tailwindcss-animate@1.0.7: + resolution: {integrity: sha512-bl6mpH3T7I3UFxuvDEXLxy/VuFxBk5bbzplh7tXI68mwMokNYd1t9qPBHlnyTwfa4JGC4zP516I1hYYtQ/vspA==} + peerDependencies: + tailwindcss: '>=3.0.0 || insiders' + tailwindcss@3.4.19: resolution: {integrity: sha512-3ofp+LL8E+pK/JuPLPggVAIaEuhvIz4qNcf3nA1Xn2o/7fb7s/TYpHhwGDv1ZU3PkBluUVaF8PyCHcm48cKLWQ==} engines: {node: '>=14.0.0'} @@ -5355,6 +6774,9 @@ packages: tiny-inflate@1.0.3: resolution: {integrity: sha512-pkY1fj1cKHb2seWDy0B16HeWyczlJA9/WW3u3c4z/NiWDsO3DOU5D7nhTLE9CF0yXv/QZFY7sEJmj24dK+Rrqw==} + tiny-invariant@1.3.3: + resolution: {integrity: sha512-+FbBPE1o9QAYvviau/qC5SE3caw21q3xkvWKBtja5vgqOWIHHJ3ioaq1VPfn/Szqctz2bU/oYeKd9/z5BL+PVg==} + tinybench@2.9.0: resolution: {integrity: sha512-0+DUvqWMValLmha6lr4kD8iAMK1HzV0/aKnCtWb9v9641TnP/MFb7Pc2bxoxQjTXAErryXVgUOfv2YqNllqGeg==} @@ -5381,6 +6803,9 @@ packages: resolution: {integrity: sha512-n1cw8k1k0x4pgA2+9XrOkFydTerNcJ1zWCO5Nn9scWHTD+5tp8dghT2x1uduQePZTZgd3Tupf+x9BxJjeJi77Q==} engines: {node: '>=14.0.0'} + tm-themes@1.12.2: + resolution: {integrity: sha512-DDcp7Feso0zvb8McGdChR1elzS0kWYcaGjxcz1R3L88xv3hvN9wP3GvOagj5JKexFrPneiGOoU5AZELXTWk4oA==} + to-buffer@1.2.2: resolution: {integrity: sha512-db0E3UJjcFhpDhAF4tLo03oli3pwl3dbnzXOUIlRKrp+ldk/VUxzpWYZENsw2SZiuBjHAk7DfB0VU7NKdpb6sw==} engines: {node: '>= 0.4'} @@ -5406,6 +6831,10 @@ packages: ts-algebra@2.0.0: resolution: {integrity: sha512-FPAhNPFMrkwz76P7cdjdmiShwMynZYN6SgOujD1urY4oNm80Ou9oMdmbR45LotcKOXoy7wSmHkRFE6Mxbrhefw==} + ts-dedent@2.3.0: + resolution: {integrity: sha512-JfJeIHke7y2egdGGgRAvpCwYFUsHlM2gPcrVOxFkznt/4uzQ7HFmvE63iFHVLBJNDuyDOQgijDK/tXH/f6Msjg==} + engines: {node: '>=6.10'} + ts-interface-checker@0.1.13: resolution: {integrity: sha512-Y/arvbn+rrz3JCKl9C4kVNfTfSm2/mEp5FSz5EsZSANGPSlQrpRI5M4PKF+mJnE52jOO90PnPSc3Ur3bTQw0gA==} @@ -5468,6 +6897,12 @@ packages: engines: {node: '>=14.17'} hasBin: true + typesense@2.1.0: + resolution: {integrity: sha512-a/IRTL+dRXlpRDU4UodyGj8hl5xBz3nKihVRd/KfSFAfFPGcpdX6lxIgwdXy3O6VLNNiEsN8YwIsPHQPVT0vNw==} + engines: {node: '>=18'} + peerDependencies: + '@babel/runtime': ^7.23.2 + uc.micro@2.1.0: resolution: {integrity: sha512-ARDJmphmdvUk6Glw7y9DQ2bFkKBHwQHLi2lsaH6PPmz/Ka9sFOBsBluozhDltWmnv9u/cF6Rt87znRTPV+yp/A==} @@ -5500,9 +6935,15 @@ packages: unifont@0.7.4: resolution: {integrity: sha512-oHeis4/xl42HUIeHuNZRGEvxj5AaIKR+bHPNegRq5LV1gdc3jundpONbjglKpihmJf+dswygdMJn3eftGIMemg==} + unist-util-filter@5.0.1: + resolution: {integrity: sha512-pHx7D4Zt6+TsfwylH9+lYhBhzyhEnCXs/lbq/Hstxno5z4gVdyc2WEW0asfjGKPyG4pEKrnBv5hdkO6+aRnQJw==} + unist-util-find-after@5.0.0: resolution: {integrity: sha512-amQa0Ep2m6hE2g72AugUItjbuM8X8cGQnFoHk0pGfrFeT9GZhzN5SW8nRsiGKK7Aif4CrACPENkA6P/Lw6fHGQ==} + unist-util-is@5.2.1: + resolution: {integrity: sha512-u9njyyfEh43npf1M+yGKDGVPbY/JWEemg5nH05ncKPfi+kBbKBJoTdsogMu33uhytuLlv9y0O7GH7fEdwLdLQw==} + unist-util-is@6.0.1: resolution: {integrity: sha512-LsiILbtBETkDz8I9p1dQ0uyRUWuaQzd/cuEeS1hoRSyW5E5XGmTzlwY1OrNzzakGowI9Dr/I8HVaw4hTtnxy8g==} @@ -5524,9 +6965,15 @@ packages: unist-util-visit-children@3.0.0: resolution: {integrity: sha512-RgmdTfSBOg04sdPcpTSD1jzoNBjt9a80/ZCzp5cI9n1qPzLZWF9YdvWGN2zmTumP1HWhXKdUWexjy/Wy/lJ7tA==} + unist-util-visit-parents@5.1.3: + resolution: {integrity: sha512-x6+y8g7wWMyQhL1iZfhIPhDAs7Xwbn9nRosDXl7qoPTSCy0yNxnKc+hWokFifWQIDGi154rdUqKvbCa4+1kLhg==} + unist-util-visit-parents@6.0.2: resolution: {integrity: sha512-goh1s1TBrqSqukSc8wrjwWhL0hiJxgA8m4kFxGlQ+8FYQ3C/m11FcTs4YYem7V664AhHVvgoQLk890Ssdsr2IQ==} + unist-util-visit@4.1.2: + resolution: {integrity: sha512-MSd8OUGISqHdVvfY9TPhyK2VdUrPgxkUtWSuMHF6XAAFuL4LokseigBnZtPnJMu+FbynTkFNnFlyjxpVKujMRg==} + unist-util-visit@5.1.0: resolution: {integrity: sha512-m+vIdyeCOpdr/QeQCu2EzxX/ohgS8KbnPDgFni4dQsfSCtpz8UqDyY5GjRru8PDKuYn7Fq19j1CQ+nJSsGKOzg==} @@ -5606,6 +7053,37 @@ packages: resolution: {integrity: sha512-oCwdVC7mTuWiPyjLUz/COz5TLk6wgp0RCsN+wHZ2Ekneac9w8uuV0njcbbie2ME+Vs+d6duwmYuR3HgQXs1fOg==} engines: {node: '>= 0.4'} + use-callback-ref@1.3.3: + resolution: {integrity: sha512-jQL3lRnocaFtu3V00JToYz/4QkNWswxijDaCVNZRiRTO3HQDLsdu1ZtmIUvV4yPp+rvWm5j0y0TG/S61cuijTg==} + engines: {node: '>=10'} + peerDependencies: + '@types/react': '*' + react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + + use-sidecar@1.1.3: + resolution: {integrity: sha512-Fedw0aZvkhynoPYlA5WXrMCAMm+nSWdZt6lzJQ7Ok8S6Q+VsHmHpRWndVRJ8Be0ZbkfPc5LRYH+5XrzXcEeLRQ==} + engines: {node: '>=10'} + peerDependencies: + '@types/react': '*' + react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + + use-sync-external-store@1.6.0: + resolution: {integrity: sha512-Pp6GSwGP/NrPIrxVFAIkOQeyw8lFenOHijQWkUTrDvrF4ALqylP2C/KCkeS9dpUM3KvYRQhna5vt7IL95+ZQ9w==} + peerDependencies: + react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 + + usehooks-ts@3.1.1: + resolution: {integrity: sha512-I4diPp9Cq6ieSUH2wu+fDAVQO43xwtulo+fKEidHUwZPnYImbtkTjzIJYcDcJqxgmX31GVqNFURodvcgHcW0pA==} + engines: {node: '>=16.15.0'} + peerDependencies: + react: ^16.8.0 || ^17 || ^18 || ^19 || ^19.0.0-rc + util-deprecate@1.0.2: resolution: {integrity: sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==} @@ -5617,6 +7095,10 @@ packages: deprecated: uuid@10 and below is no longer supported. For ESM codebases, update to uuid@latest. For CommonJS codebases, use uuid@11 (but be aware this version will likely be deprecated in 2028). hasBin: true + uuid@14.0.1: + resolution: {integrity: sha512-6ZxzVpzDXDa3bJWaHilVayA+BH/1zmxCJoVgvmqJnid/gPoKHxUrS/aC/T6LGQtNHT+XHG9fXPJB4d+IrU30Ew==} + hasBin: true + vary@1.1.2: resolution: {integrity: sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==} engines: {node: '>= 0.8'} @@ -5630,6 +7112,9 @@ packages: vfile@6.0.3: resolution: {integrity: sha512-KzIbH/9tXat2u30jf+smMwFCsno4wHVdNmzFyL+T/L3UGqqk6JKfVqOFOZEpZSHADH1k40ab6NUIXZq422ov3Q==} + victory-vendor@36.9.2: + resolution: {integrity: sha512-PnpQQMuxlwYdocC8fIJqVXvkeViHYzotI+NJrCuav0ZYFoq912ZHBk3mCeuj+5/VpodOjPe1z0Fk2ihgzlXqjQ==} + vite-node@2.1.9: resolution: {integrity: sha512-AM9aQ/IPrW/6ENLQg3AGY4K1N2TGZdR5e4gu/MmmR2xR3Ll1+dib+nook92g4TV3PXVyeyxdWwtaCAiUL0hMxA==} engines: {node: ^18.0.0 || >=20.0.0} @@ -5742,6 +7227,9 @@ packages: vm-browserify@1.1.2: resolution: {integrity: sha512-2ham8XPWTONajOR0ohOKOHXkm3+gaBmGut3SRuu75xLd/RRaY6vqgh8NBYYk7+RW3u5AtzPQZG8F10LHkl0lAQ==} + w3c-keyname@2.2.8: + resolution: {integrity: sha512-dpojBhNsCNN7T82Tm7k26A6G9ML3NkhDsnw9n/eoxSRlVBB4CEtIQ/KTCLI2Fwf3ataSXRhYFkQi3SlnFwPvPQ==} + web-namespaces@2.0.1: resolution: {integrity: sha512-bKr1DkiNa2krS7qxNtdrtHAmzuYGFQLiQ13TsorsdT6ULTkPLKuu5+GsFpDlg6JFjUTwX2DyhMPG2be8uPrqsQ==} @@ -5749,6 +7237,9 @@ packages: resolution: {integrity: sha512-d2JWLCivmZYTSIoge9MsgFCZrt571BikcWGYkjC1khllbTeDlGqZ2D8vD8E/lJa8WGWbb7Plm8/XJYV7IJHZZw==} engines: {node: '>= 8'} + web-vitals@5.3.0: + resolution: {integrity: sha512-q6LWsLatGYZp5VGBIOvbTj6JBV2nOmC8KvWztXBmwJcfFAzhwKwbOxhUH306XY3CcaZDUlSmSuNPBsCn0bFu+g==} + which-pm-runs@1.1.0: resolution: {integrity: sha512-n1brCuqClxfFfq/Rb0ICg9giSZqCS+pLtccdag6C2HyufBrh3fBOiy9nb6ggRMvWOVH5GrdJskj5iGTZNxd7SA==} engines: {node: '>=4'} @@ -5869,6 +7360,24 @@ packages: zod@4.3.6: resolution: {integrity: sha512-rftlrkhHZOcjDwkGlnUtZZkvaPHCsDATp4pGpuOOMDaTdDDXF91wuVDJoWoPsKX/3YPQ5fHuF3STjcYyKr+Qhg==} + zustand@5.0.14: + resolution: {integrity: sha512-/8tAspM5LMPr28b3fwLYrtdj77ECpfZviaP75CMTnwO8ISyaE4GDIG/9rDDYq/cH9D2Xw2A2RXglLInmVBQB/g==} + engines: {node: '>=12.20.0'} + peerDependencies: + '@types/react': '>=18.0.0' + immer: '>=9.0.6' + react: '>=18.0.0' + use-sync-external-store: '>=1.2.0' + peerDependenciesMeta: + '@types/react': + optional: true + immer: + optional: true + react: + optional: true + use-sync-external-store: + optional: true + zwitch@2.0.4: resolution: {integrity: sha512-bXE4cR/kVZhKZX/RjPEflHaKVhUVl85noU3v6b8apfQEc1x4A+zBxjZ4lN8LqGd6WZ3dl98pY4o717VFmoPp+A==} @@ -5884,6 +7393,11 @@ snapshots: '@alloc/quick-lru@5.2.0': {} + '@antfu/install-pkg@1.1.0': + dependencies: + package-manager-detector: 1.6.0 + tinyexec: 1.2.4 + '@anthropic-ai/claude-agent-sdk@0.2.87(zod@4.3.6)': dependencies: '@anthropic-ai/sdk': 0.74.0(zod@4.3.6) @@ -6003,39 +7517,6 @@ snapshots: stream-replace-string: 2.0.0 zod: 4.3.6 - '@astrojs/starlight@0.36.3(astro@5.18.2(@types/node@24.13.2)(jiti@1.21.7)(rollup@4.60.1)(tsx@4.21.0)(typescript@5.9.3)(yaml@2.9.0))': - dependencies: - '@astrojs/markdown-remark': 6.3.11 - '@astrojs/mdx': 4.3.14(astro@5.18.2(@types/node@24.13.2)(jiti@1.21.7)(rollup@4.60.1)(tsx@4.21.0)(typescript@5.9.3)(yaml@2.9.0)) - '@astrojs/sitemap': 3.7.3 - '@pagefind/default-ui': 1.5.2 - '@types/hast': 3.0.4 - '@types/js-yaml': 4.0.9 - '@types/mdast': 4.0.4 - astro: 5.18.2(@types/node@24.13.2)(jiti@1.21.7)(rollup@4.60.1)(tsx@4.21.0)(typescript@5.9.3)(yaml@2.9.0) - astro-expressive-code: 0.41.7(astro@5.18.2(@types/node@24.13.2)(jiti@1.21.7)(rollup@4.60.1)(tsx@4.21.0)(typescript@5.9.3)(yaml@2.9.0)) - bcp-47: 2.1.0 - hast-util-from-html: 2.0.3 - hast-util-select: 6.0.4 - hast-util-to-string: 3.0.1 - hastscript: 9.0.1 - i18next: 23.16.8 - js-yaml: 4.2.0 - klona: 2.0.6 - mdast-util-directive: 3.1.0 - mdast-util-to-markdown: 2.1.2 - mdast-util-to-string: 4.0.0 - pagefind: 1.5.2 - rehype: 13.0.2 - rehype-format: 5.0.1 - remark-directive: 3.0.1 - ultrahtml: 1.6.0 - unified: 11.0.5 - unist-util-visit: 5.1.0 - vfile: 6.0.3 - transitivePeerDependencies: - - supports-color - '@astrojs/tailwind@6.0.2(astro@5.18.2(@types/node@24.13.2)(jiti@1.21.7)(rollup@4.60.1)(tsx@4.21.0)(typescript@5.9.3)(yaml@2.9.0))(tailwindcss@3.4.19(tsx@4.21.0)(yaml@2.9.0))': dependencies: astro: 5.18.2(@types/node@24.13.2)(jiti@1.21.7)(rollup@4.60.1)(tsx@4.21.0)(typescript@5.9.3)(yaml@2.9.0) @@ -6441,11 +7922,81 @@ snapshots: '@borewit/text-codec@0.2.2': {} + '@braintree/sanitize-url@7.1.2': {} + '@capsizecss/unpack@4.0.1': dependencies: fontkitten: 1.0.3 - '@ctrl/tinycolor@4.2.0': {} + '@chevrotain/types@11.1.2': {} + + '@codemirror/autocomplete@6.20.3': + dependencies: + '@codemirror/language': 6.12.4 + '@codemirror/state': 6.7.0 + '@codemirror/view': 6.43.4 + '@lezer/common': 1.5.2 + + '@codemirror/commands@6.10.4': + dependencies: + '@codemirror/language': 6.12.4 + '@codemirror/state': 6.7.0 + '@codemirror/view': 6.43.4 + '@lezer/common': 1.5.2 + + '@codemirror/lang-javascript@6.2.5': + dependencies: + '@codemirror/autocomplete': 6.20.3 + '@codemirror/language': 6.12.4 + '@codemirror/lint': 6.9.7 + '@codemirror/state': 6.7.0 + '@codemirror/view': 6.43.4 + '@lezer/common': 1.5.2 + '@lezer/javascript': 1.5.4 + + '@codemirror/lang-json@6.0.2': + dependencies: + '@codemirror/language': 6.12.4 + '@lezer/json': 1.0.3 + + '@codemirror/language@6.12.4': + dependencies: + '@codemirror/state': 6.7.0 + '@codemirror/view': 6.43.4 + '@lezer/common': 1.5.2 + '@lezer/highlight': 1.2.3 + '@lezer/lr': 1.4.10 + style-mod: 4.1.3 + + '@codemirror/lint@6.9.7': + dependencies: + '@codemirror/state': 6.7.0 + '@codemirror/view': 6.43.4 + crelt: 1.0.7 + + '@codemirror/search@6.7.1': + dependencies: + '@codemirror/state': 6.7.0 + '@codemirror/view': 6.43.4 + crelt: 1.0.7 + + '@codemirror/state@6.7.0': + dependencies: + '@marijn/find-cluster-break': 1.0.3 + + '@codemirror/theme-one-dark@6.1.3': + dependencies: + '@codemirror/language': 6.12.4 + '@codemirror/state': 6.7.0 + '@codemirror/view': 6.43.4 + '@lezer/highlight': 1.2.3 + + '@codemirror/view@6.43.4': + dependencies: + '@codemirror/state': 6.7.0 + crelt: 1.0.7 + style-mod: 4.1.3 + w3c-keyname: 2.2.8 '@emnapi/runtime@1.11.1': dependencies: @@ -6653,54 +8204,95 @@ snapshots: '@esbuild/win32-arm64@0.21.5': optional: true - '@esbuild/win32-arm64@0.25.12': - optional: true + '@esbuild/win32-arm64@0.25.12': + optional: true + + '@esbuild/win32-arm64@0.27.4': + optional: true + + '@esbuild/win32-ia32@0.21.5': + optional: true + + '@esbuild/win32-ia32@0.25.12': + optional: true + + '@esbuild/win32-ia32@0.27.4': + optional: true + + '@esbuild/win32-x64@0.21.5': + optional: true + + '@esbuild/win32-x64@0.25.12': + optional: true + + '@esbuild/win32-x64@0.27.4': + optional: true + + '@floating-ui/core@1.7.5': + dependencies: + '@floating-ui/utils': 0.2.11 + + '@floating-ui/dom@1.7.6': + dependencies: + '@floating-ui/core': 1.7.5 + '@floating-ui/utils': 0.2.11 + + '@floating-ui/react-dom@2.1.8(react-dom@19.2.7(react@19.2.7))(react@19.2.7)': + dependencies: + '@floating-ui/dom': 1.7.6 + react: 19.2.7 + react-dom: 19.2.7(react@19.2.7) + + '@floating-ui/react@0.26.28(react-dom@19.2.7(react@19.2.7))(react@19.2.7)': + dependencies: + '@floating-ui/react-dom': 2.1.8(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + '@floating-ui/utils': 0.2.11 + react: 19.2.7 + react-dom: 19.2.7(react@19.2.7) + tabbable: 6.5.0 + + '@floating-ui/utils@0.2.11': {} - '@esbuild/win32-arm64@0.27.4': - optional: true + '@fortawesome/fontawesome-common-types@6.7.2': {} - '@esbuild/win32-ia32@0.21.5': - optional: true + '@fortawesome/fontawesome-common-types@7.3.0': {} - '@esbuild/win32-ia32@0.25.12': - optional: true + '@fortawesome/fontawesome-free@6.7.2': {} - '@esbuild/win32-ia32@0.27.4': - optional: true + '@fortawesome/fontawesome-svg-core@6.7.2': + dependencies: + '@fortawesome/fontawesome-common-types': 6.7.2 - '@esbuild/win32-x64@0.21.5': - optional: true + '@fortawesome/fontawesome-svg-core@7.3.0': + dependencies: + '@fortawesome/fontawesome-common-types': 7.3.0 - '@esbuild/win32-x64@0.25.12': - optional: true + '@fortawesome/free-brands-svg-icons@6.7.2': + dependencies: + '@fortawesome/fontawesome-common-types': 6.7.2 - '@esbuild/win32-x64@0.27.4': - optional: true + '@fortawesome/free-brands-svg-icons@7.3.0': + dependencies: + '@fortawesome/fontawesome-common-types': 7.3.0 - '@expressive-code/core@0.41.7': + '@fortawesome/free-solid-svg-icons@6.7.2': dependencies: - '@ctrl/tinycolor': 4.2.0 - hast-util-select: 6.0.4 - hast-util-to-html: 9.0.5 - hast-util-to-text: 4.0.2 - hastscript: 9.0.1 - postcss: 8.5.8 - postcss-nested: 6.2.0(postcss@8.5.8) - unist-util-visit: 5.1.0 - unist-util-visit-parents: 6.0.2 + '@fortawesome/fontawesome-common-types': 6.7.2 - '@expressive-code/plugin-frames@0.41.7': + '@fortawesome/free-solid-svg-icons@7.3.0': dependencies: - '@expressive-code/core': 0.41.7 + '@fortawesome/fontawesome-common-types': 7.3.0 - '@expressive-code/plugin-shiki@0.41.7': + '@fortawesome/react-fontawesome@0.2.6(@fortawesome/fontawesome-svg-core@6.7.2)(react@19.2.7)': dependencies: - '@expressive-code/core': 0.41.7 - shiki: 3.23.0 + '@fortawesome/fontawesome-svg-core': 6.7.2 + prop-types: 15.8.1 + react: 19.2.7 - '@expressive-code/plugin-text-markers@0.41.7': + '@fortawesome/react-fontawesome@3.3.1(@fortawesome/fontawesome-svg-core@7.3.0)(react@19.2.7)': dependencies: - '@expressive-code/core': 0.41.7 + '@fortawesome/fontawesome-svg-core': 7.3.0 + react: 19.2.7 '@gerrit0/mini-shiki@3.23.0': dependencies: @@ -6745,10 +8337,32 @@ snapshots: yargs: 17.7.2 optional: true + '@headlessui/react@2.2.10(react-dom@19.2.7(react@19.2.7))(react@19.2.7)': + dependencies: + '@floating-ui/react': 0.26.28(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + '@react-aria/focus': 3.22.1(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + '@react-aria/interactions': 3.28.1(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + '@tanstack/react-virtual': 3.14.4(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + react: 19.2.7 + react-dom: 19.2.7(react@19.2.7) + use-sync-external-store: 1.6.0(react@19.2.7) + '@hono/node-server@1.19.14(hono@4.12.27)': dependencies: hono: 4.12.27 + '@hookform/resolvers@3.10.0(react-hook-form@7.80.0(react@19.2.7))': + dependencies: + react-hook-form: 7.80.0(react@19.2.7) + + '@iconify/types@2.0.0': {} + + '@iconify/utils@3.1.3': + dependencies: + '@antfu/install-pkg': 1.1.0 + '@iconify/types': 2.0.0 + import-meta-resolve: 4.2.0 + '@img/colour@1.1.0': optional: true @@ -6921,6 +8535,18 @@ snapshots: '@img/sharp-win32-x64@0.34.5': optional: true + '@internationalized/date@3.12.2': + dependencies: + '@swc/helpers': 0.5.23 + + '@internationalized/number@3.6.7': + dependencies: + '@swc/helpers': 0.5.23 + + '@internationalized/string@3.2.9': + dependencies: + '@swc/helpers': 0.5.23 + '@isaacs/cliui@8.0.2': dependencies: string-width: 5.1.2 @@ -6952,6 +8578,30 @@ snapshots: '@js-sdsl/ordered-map@4.4.2': optional: true + '@lezer/common@1.5.2': {} + + '@lezer/highlight@1.2.3': + dependencies: + '@lezer/common': 1.5.2 + + '@lezer/javascript@1.5.4': + dependencies: + '@lezer/common': 1.5.2 + '@lezer/highlight': 1.2.3 + '@lezer/lr': 1.4.10 + + '@lezer/json@1.0.3': + dependencies: + '@lezer/common': 1.5.2 + '@lezer/highlight': 1.2.3 + '@lezer/lr': 1.4.10 + + '@lezer/lr@1.4.10': + dependencies: + '@lezer/common': 1.5.2 + + '@marijn/find-cluster-break@1.0.3': {} + '@mariozechner/clipboard-darwin-arm64@0.3.9': optional: true @@ -7171,6 +8821,10 @@ snapshots: transitivePeerDependencies: - supports-color + '@mermaid-js/parser@1.2.0': + dependencies: + '@chevrotain/types': 11.1.2 + '@mistralai/mistralai@1.14.1': dependencies: ws: 8.21.0 @@ -7228,87 +8882,831 @@ snapshots: '@oven/bun-linux-aarch64-musl@1.3.11': optional: true - '@oven/bun-linux-aarch64@1.3.11': - optional: true + '@oven/bun-linux-aarch64@1.3.11': + optional: true + + '@oven/bun-linux-x64-baseline@1.3.11': + optional: true + + '@oven/bun-linux-x64-musl-baseline@1.3.11': + optional: true + + '@oven/bun-linux-x64-musl@1.3.11': + optional: true + + '@oven/bun-linux-x64@1.3.11': + optional: true + + '@oven/bun-windows-aarch64@1.3.11': + optional: true + + '@oven/bun-windows-x64-baseline@1.3.11': + optional: true + + '@oven/bun-windows-x64@1.3.11': + optional: true + + '@pkgjs/parseargs@0.11.0': + optional: true + + '@playwright/test@1.59.1': + dependencies: + playwright: 1.59.1 + + '@posthog/core@1.38.0': + dependencies: + '@posthog/types': 1.391.1 + + '@posthog/types@1.391.1': {} + + '@protobufjs/aspromise@1.1.2': {} + + '@protobufjs/base64@1.1.2': {} + + '@protobufjs/codegen@2.0.4': {} + + '@protobufjs/eventemitter@1.1.0': {} + + '@protobufjs/fetch@1.1.0': + dependencies: + '@protobufjs/aspromise': 1.1.2 + '@protobufjs/inquire': 1.1.0 + + '@protobufjs/float@1.0.2': {} + + '@protobufjs/inquire@1.1.0': {} + + '@protobufjs/path@1.1.2': {} + + '@protobufjs/pool@1.1.0': {} + + '@protobufjs/utf8@1.1.0': {} + + '@radix-ui/number@1.1.2': {} + + '@radix-ui/primitive@1.1.4': {} + + '@radix-ui/react-accordion@1.2.14(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)': + dependencies: + '@radix-ui/primitive': 1.1.4 + '@radix-ui/react-collapsible': 1.1.14(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + '@radix-ui/react-collection': 1.1.10(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + '@radix-ui/react-compose-refs': 1.1.3(@types/react@19.2.17)(react@19.2.7) + '@radix-ui/react-context': 1.1.4(@types/react@19.2.17)(react@19.2.7) + '@radix-ui/react-direction': 1.1.2(@types/react@19.2.17)(react@19.2.7) + '@radix-ui/react-id': 1.1.2(@types/react@19.2.17)(react@19.2.7) + '@radix-ui/react-primitive': 2.1.6(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + '@radix-ui/react-use-controllable-state': 1.2.3(@types/react@19.2.17)(react@19.2.7) + react: 19.2.7 + react-dom: 19.2.7(react@19.2.7) + optionalDependencies: + '@types/react': 19.2.17 + '@types/react-dom': 19.2.3(@types/react@19.2.17) + + '@radix-ui/react-arrow@1.1.10(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)': + dependencies: + '@radix-ui/react-primitive': 2.1.6(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + react: 19.2.7 + react-dom: 19.2.7(react@19.2.7) + optionalDependencies: + '@types/react': 19.2.17 + '@types/react-dom': 19.2.3(@types/react@19.2.17) + + '@radix-ui/react-avatar@1.2.0(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)': + dependencies: + '@radix-ui/react-context': 1.1.4(@types/react@19.2.17)(react@19.2.7) + '@radix-ui/react-primitive': 2.1.6(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + '@radix-ui/react-use-callback-ref': 1.1.2(@types/react@19.2.17)(react@19.2.7) + '@radix-ui/react-use-is-hydrated': 0.1.1(@types/react@19.2.17)(react@19.2.7) + '@radix-ui/react-use-layout-effect': 1.1.2(@types/react@19.2.17)(react@19.2.7) + react: 19.2.7 + react-dom: 19.2.7(react@19.2.7) + optionalDependencies: + '@types/react': 19.2.17 + '@types/react-dom': 19.2.3(@types/react@19.2.17) + + '@radix-ui/react-checkbox@1.3.5(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)': + dependencies: + '@radix-ui/primitive': 1.1.4 + '@radix-ui/react-compose-refs': 1.1.3(@types/react@19.2.17)(react@19.2.7) + '@radix-ui/react-context': 1.1.4(@types/react@19.2.17)(react@19.2.7) + '@radix-ui/react-presence': 1.1.6(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + '@radix-ui/react-primitive': 2.1.6(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + '@radix-ui/react-use-controllable-state': 1.2.3(@types/react@19.2.17)(react@19.2.7) + '@radix-ui/react-use-previous': 1.1.2(@types/react@19.2.17)(react@19.2.7) + '@radix-ui/react-use-size': 1.1.2(@types/react@19.2.17)(react@19.2.7) + react: 19.2.7 + react-dom: 19.2.7(react@19.2.7) + optionalDependencies: + '@types/react': 19.2.17 + '@types/react-dom': 19.2.3(@types/react@19.2.17) + + '@radix-ui/react-collapsible@1.1.14(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)': + dependencies: + '@radix-ui/primitive': 1.1.4 + '@radix-ui/react-compose-refs': 1.1.3(@types/react@19.2.17)(react@19.2.7) + '@radix-ui/react-context': 1.1.4(@types/react@19.2.17)(react@19.2.7) + '@radix-ui/react-id': 1.1.2(@types/react@19.2.17)(react@19.2.7) + '@radix-ui/react-presence': 1.1.6(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + '@radix-ui/react-primitive': 2.1.6(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + '@radix-ui/react-use-controllable-state': 1.2.3(@types/react@19.2.17)(react@19.2.7) + '@radix-ui/react-use-layout-effect': 1.1.2(@types/react@19.2.17)(react@19.2.7) + react: 19.2.7 + react-dom: 19.2.7(react@19.2.7) + optionalDependencies: + '@types/react': 19.2.17 + '@types/react-dom': 19.2.3(@types/react@19.2.17) + + '@radix-ui/react-collection@1.1.10(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)': + dependencies: + '@radix-ui/react-compose-refs': 1.1.3(@types/react@19.2.17)(react@19.2.7) + '@radix-ui/react-context': 1.1.4(@types/react@19.2.17)(react@19.2.7) + '@radix-ui/react-primitive': 2.1.6(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + '@radix-ui/react-slot': 1.3.0(@types/react@19.2.17)(react@19.2.7) + react: 19.2.7 + react-dom: 19.2.7(react@19.2.7) + optionalDependencies: + '@types/react': 19.2.17 + '@types/react-dom': 19.2.3(@types/react@19.2.17) + + '@radix-ui/react-compose-refs@1.1.3(@types/react@19.2.17)(react@19.2.7)': + dependencies: + react: 19.2.7 + optionalDependencies: + '@types/react': 19.2.17 + + '@radix-ui/react-context-menu@2.3.1(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)': + dependencies: + '@radix-ui/primitive': 1.1.4 + '@radix-ui/react-context': 1.1.4(@types/react@19.2.17)(react@19.2.7) + '@radix-ui/react-menu': 2.1.18(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + '@radix-ui/react-primitive': 2.1.6(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + '@radix-ui/react-use-controllable-state': 1.2.3(@types/react@19.2.17)(react@19.2.7) + react: 19.2.7 + react-dom: 19.2.7(react@19.2.7) + optionalDependencies: + '@types/react': 19.2.17 + '@types/react-dom': 19.2.3(@types/react@19.2.17) + + '@radix-ui/react-context@1.1.4(@types/react@19.2.17)(react@19.2.7)': + dependencies: + react: 19.2.7 + optionalDependencies: + '@types/react': 19.2.17 + + '@radix-ui/react-dialog@1.1.17(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)': + dependencies: + '@radix-ui/primitive': 1.1.4 + '@radix-ui/react-compose-refs': 1.1.3(@types/react@19.2.17)(react@19.2.7) + '@radix-ui/react-context': 1.1.4(@types/react@19.2.17)(react@19.2.7) + '@radix-ui/react-dismissable-layer': 1.1.13(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + '@radix-ui/react-focus-guards': 1.1.4(@types/react@19.2.17)(react@19.2.7) + '@radix-ui/react-focus-scope': 1.1.10(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + '@radix-ui/react-id': 1.1.2(@types/react@19.2.17)(react@19.2.7) + '@radix-ui/react-portal': 1.1.12(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + '@radix-ui/react-presence': 1.1.6(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + '@radix-ui/react-primitive': 2.1.6(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + '@radix-ui/react-slot': 1.3.0(@types/react@19.2.17)(react@19.2.7) + '@radix-ui/react-use-controllable-state': 1.2.3(@types/react@19.2.17)(react@19.2.7) + aria-hidden: 1.2.6 + react: 19.2.7 + react-dom: 19.2.7(react@19.2.7) + react-remove-scroll: 2.7.2(@types/react@19.2.17)(react@19.2.7) + optionalDependencies: + '@types/react': 19.2.17 + '@types/react-dom': 19.2.3(@types/react@19.2.17) + + '@radix-ui/react-direction@1.1.2(@types/react@19.2.17)(react@19.2.7)': + dependencies: + react: 19.2.7 + optionalDependencies: + '@types/react': 19.2.17 + + '@radix-ui/react-dismissable-layer@1.1.13(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)': + dependencies: + '@radix-ui/primitive': 1.1.4 + '@radix-ui/react-compose-refs': 1.1.3(@types/react@19.2.17)(react@19.2.7) + '@radix-ui/react-primitive': 2.1.6(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + '@radix-ui/react-use-callback-ref': 1.1.2(@types/react@19.2.17)(react@19.2.7) + '@radix-ui/react-use-escape-keydown': 1.1.2(@types/react@19.2.17)(react@19.2.7) + react: 19.2.7 + react-dom: 19.2.7(react@19.2.7) + optionalDependencies: + '@types/react': 19.2.17 + '@types/react-dom': 19.2.3(@types/react@19.2.17) + + '@radix-ui/react-dropdown-menu@2.1.18(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)': + dependencies: + '@radix-ui/primitive': 1.1.4 + '@radix-ui/react-compose-refs': 1.1.3(@types/react@19.2.17)(react@19.2.7) + '@radix-ui/react-context': 1.1.4(@types/react@19.2.17)(react@19.2.7) + '@radix-ui/react-id': 1.1.2(@types/react@19.2.17)(react@19.2.7) + '@radix-ui/react-menu': 2.1.18(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + '@radix-ui/react-primitive': 2.1.6(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + '@radix-ui/react-use-controllable-state': 1.2.3(@types/react@19.2.17)(react@19.2.7) + react: 19.2.7 + react-dom: 19.2.7(react@19.2.7) + optionalDependencies: + '@types/react': 19.2.17 + '@types/react-dom': 19.2.3(@types/react@19.2.17) + + '@radix-ui/react-focus-guards@1.1.4(@types/react@19.2.17)(react@19.2.7)': + dependencies: + react: 19.2.7 + optionalDependencies: + '@types/react': 19.2.17 + + '@radix-ui/react-focus-scope@1.1.10(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)': + dependencies: + '@radix-ui/react-compose-refs': 1.1.3(@types/react@19.2.17)(react@19.2.7) + '@radix-ui/react-primitive': 2.1.6(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + '@radix-ui/react-use-callback-ref': 1.1.2(@types/react@19.2.17)(react@19.2.7) + react: 19.2.7 + react-dom: 19.2.7(react@19.2.7) + optionalDependencies: + '@types/react': 19.2.17 + '@types/react-dom': 19.2.3(@types/react@19.2.17) + + '@radix-ui/react-id@1.1.2(@types/react@19.2.17)(react@19.2.7)': + dependencies: + '@radix-ui/react-use-layout-effect': 1.1.2(@types/react@19.2.17)(react@19.2.7) + react: 19.2.7 + optionalDependencies: + '@types/react': 19.2.17 + + '@radix-ui/react-label@2.1.10(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)': + dependencies: + '@radix-ui/react-primitive': 2.1.6(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + react: 19.2.7 + react-dom: 19.2.7(react@19.2.7) + optionalDependencies: + '@types/react': 19.2.17 + '@types/react-dom': 19.2.3(@types/react@19.2.17) + + '@radix-ui/react-menu@2.1.18(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)': + dependencies: + '@radix-ui/primitive': 1.1.4 + '@radix-ui/react-collection': 1.1.10(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + '@radix-ui/react-compose-refs': 1.1.3(@types/react@19.2.17)(react@19.2.7) + '@radix-ui/react-context': 1.1.4(@types/react@19.2.17)(react@19.2.7) + '@radix-ui/react-direction': 1.1.2(@types/react@19.2.17)(react@19.2.7) + '@radix-ui/react-dismissable-layer': 1.1.13(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + '@radix-ui/react-focus-guards': 1.1.4(@types/react@19.2.17)(react@19.2.7) + '@radix-ui/react-focus-scope': 1.1.10(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + '@radix-ui/react-id': 1.1.2(@types/react@19.2.17)(react@19.2.7) + '@radix-ui/react-popper': 1.3.1(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + '@radix-ui/react-portal': 1.1.12(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + '@radix-ui/react-presence': 1.1.6(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + '@radix-ui/react-primitive': 2.1.6(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + '@radix-ui/react-roving-focus': 1.1.13(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + '@radix-ui/react-slot': 1.3.0(@types/react@19.2.17)(react@19.2.7) + '@radix-ui/react-use-callback-ref': 1.1.2(@types/react@19.2.17)(react@19.2.7) + aria-hidden: 1.2.6 + react: 19.2.7 + react-dom: 19.2.7(react@19.2.7) + react-remove-scroll: 2.7.2(@types/react@19.2.17)(react@19.2.7) + optionalDependencies: + '@types/react': 19.2.17 + '@types/react-dom': 19.2.3(@types/react@19.2.17) + + '@radix-ui/react-popover@1.1.17(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)': + dependencies: + '@radix-ui/primitive': 1.1.4 + '@radix-ui/react-compose-refs': 1.1.3(@types/react@19.2.17)(react@19.2.7) + '@radix-ui/react-context': 1.1.4(@types/react@19.2.17)(react@19.2.7) + '@radix-ui/react-dismissable-layer': 1.1.13(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + '@radix-ui/react-focus-guards': 1.1.4(@types/react@19.2.17)(react@19.2.7) + '@radix-ui/react-focus-scope': 1.1.10(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + '@radix-ui/react-id': 1.1.2(@types/react@19.2.17)(react@19.2.7) + '@radix-ui/react-popper': 1.3.1(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + '@radix-ui/react-portal': 1.1.12(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + '@radix-ui/react-presence': 1.1.6(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + '@radix-ui/react-primitive': 2.1.6(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + '@radix-ui/react-slot': 1.3.0(@types/react@19.2.17)(react@19.2.7) + '@radix-ui/react-use-controllable-state': 1.2.3(@types/react@19.2.17)(react@19.2.7) + aria-hidden: 1.2.6 + react: 19.2.7 + react-dom: 19.2.7(react@19.2.7) + react-remove-scroll: 2.7.2(@types/react@19.2.17)(react@19.2.7) + optionalDependencies: + '@types/react': 19.2.17 + '@types/react-dom': 19.2.3(@types/react@19.2.17) + + '@radix-ui/react-popper@1.3.1(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)': + dependencies: + '@floating-ui/react-dom': 2.1.8(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + '@radix-ui/react-arrow': 1.1.10(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + '@radix-ui/react-compose-refs': 1.1.3(@types/react@19.2.17)(react@19.2.7) + '@radix-ui/react-context': 1.1.4(@types/react@19.2.17)(react@19.2.7) + '@radix-ui/react-primitive': 2.1.6(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + '@radix-ui/react-use-callback-ref': 1.1.2(@types/react@19.2.17)(react@19.2.7) + '@radix-ui/react-use-layout-effect': 1.1.2(@types/react@19.2.17)(react@19.2.7) + '@radix-ui/react-use-rect': 1.1.2(@types/react@19.2.17)(react@19.2.7) + '@radix-ui/react-use-size': 1.1.2(@types/react@19.2.17)(react@19.2.7) + '@radix-ui/rect': 1.1.2 + react: 19.2.7 + react-dom: 19.2.7(react@19.2.7) + optionalDependencies: + '@types/react': 19.2.17 + '@types/react-dom': 19.2.3(@types/react@19.2.17) + + '@radix-ui/react-portal@1.1.12(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)': + dependencies: + '@radix-ui/react-primitive': 2.1.6(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + '@radix-ui/react-use-layout-effect': 1.1.2(@types/react@19.2.17)(react@19.2.7) + react: 19.2.7 + react-dom: 19.2.7(react@19.2.7) + optionalDependencies: + '@types/react': 19.2.17 + '@types/react-dom': 19.2.3(@types/react@19.2.17) + + '@radix-ui/react-presence@1.1.6(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)': + dependencies: + '@radix-ui/react-use-layout-effect': 1.1.2(@types/react@19.2.17)(react@19.2.7) + react: 19.2.7 + react-dom: 19.2.7(react@19.2.7) + optionalDependencies: + '@types/react': 19.2.17 + '@types/react-dom': 19.2.3(@types/react@19.2.17) + + '@radix-ui/react-primitive@2.1.6(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)': + dependencies: + '@radix-ui/react-slot': 1.3.0(@types/react@19.2.17)(react@19.2.7) + react: 19.2.7 + react-dom: 19.2.7(react@19.2.7) + optionalDependencies: + '@types/react': 19.2.17 + '@types/react-dom': 19.2.3(@types/react@19.2.17) - '@oven/bun-linux-x64-baseline@1.3.11': - optional: true + '@radix-ui/react-progress@1.1.10(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)': + dependencies: + '@radix-ui/react-context': 1.1.4(@types/react@19.2.17)(react@19.2.7) + '@radix-ui/react-primitive': 2.1.6(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + react: 19.2.7 + react-dom: 19.2.7(react@19.2.7) + optionalDependencies: + '@types/react': 19.2.17 + '@types/react-dom': 19.2.3(@types/react@19.2.17) - '@oven/bun-linux-x64-musl-baseline@1.3.11': - optional: true + '@radix-ui/react-radio-group@1.4.1(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)': + dependencies: + '@radix-ui/primitive': 1.1.4 + '@radix-ui/react-compose-refs': 1.1.3(@types/react@19.2.17)(react@19.2.7) + '@radix-ui/react-context': 1.1.4(@types/react@19.2.17)(react@19.2.7) + '@radix-ui/react-direction': 1.1.2(@types/react@19.2.17)(react@19.2.7) + '@radix-ui/react-presence': 1.1.6(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + '@radix-ui/react-primitive': 2.1.6(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + '@radix-ui/react-roving-focus': 1.1.13(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + '@radix-ui/react-use-controllable-state': 1.2.3(@types/react@19.2.17)(react@19.2.7) + '@radix-ui/react-use-previous': 1.1.2(@types/react@19.2.17)(react@19.2.7) + '@radix-ui/react-use-size': 1.1.2(@types/react@19.2.17)(react@19.2.7) + react: 19.2.7 + react-dom: 19.2.7(react@19.2.7) + optionalDependencies: + '@types/react': 19.2.17 + '@types/react-dom': 19.2.3(@types/react@19.2.17) - '@oven/bun-linux-x64-musl@1.3.11': - optional: true + '@radix-ui/react-roving-focus@1.1.13(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)': + dependencies: + '@radix-ui/primitive': 1.1.4 + '@radix-ui/react-collection': 1.1.10(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + '@radix-ui/react-compose-refs': 1.1.3(@types/react@19.2.17)(react@19.2.7) + '@radix-ui/react-context': 1.1.4(@types/react@19.2.17)(react@19.2.7) + '@radix-ui/react-direction': 1.1.2(@types/react@19.2.17)(react@19.2.7) + '@radix-ui/react-id': 1.1.2(@types/react@19.2.17)(react@19.2.7) + '@radix-ui/react-primitive': 2.1.6(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + '@radix-ui/react-use-callback-ref': 1.1.2(@types/react@19.2.17)(react@19.2.7) + '@radix-ui/react-use-controllable-state': 1.2.3(@types/react@19.2.17)(react@19.2.7) + react: 19.2.7 + react-dom: 19.2.7(react@19.2.7) + optionalDependencies: + '@types/react': 19.2.17 + '@types/react-dom': 19.2.3(@types/react@19.2.17) - '@oven/bun-linux-x64@1.3.11': - optional: true + '@radix-ui/react-scroll-area@1.2.12(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)': + dependencies: + '@radix-ui/number': 1.1.2 + '@radix-ui/primitive': 1.1.4 + '@radix-ui/react-compose-refs': 1.1.3(@types/react@19.2.17)(react@19.2.7) + '@radix-ui/react-context': 1.1.4(@types/react@19.2.17)(react@19.2.7) + '@radix-ui/react-direction': 1.1.2(@types/react@19.2.17)(react@19.2.7) + '@radix-ui/react-presence': 1.1.6(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + '@radix-ui/react-primitive': 2.1.6(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + '@radix-ui/react-use-callback-ref': 1.1.2(@types/react@19.2.17)(react@19.2.7) + '@radix-ui/react-use-layout-effect': 1.1.2(@types/react@19.2.17)(react@19.2.7) + react: 19.2.7 + react-dom: 19.2.7(react@19.2.7) + optionalDependencies: + '@types/react': 19.2.17 + '@types/react-dom': 19.2.3(@types/react@19.2.17) - '@oven/bun-windows-aarch64@1.3.11': - optional: true + '@radix-ui/react-select@2.3.1(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)': + dependencies: + '@radix-ui/number': 1.1.2 + '@radix-ui/primitive': 1.1.4 + '@radix-ui/react-collection': 1.1.10(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + '@radix-ui/react-compose-refs': 1.1.3(@types/react@19.2.17)(react@19.2.7) + '@radix-ui/react-context': 1.1.4(@types/react@19.2.17)(react@19.2.7) + '@radix-ui/react-direction': 1.1.2(@types/react@19.2.17)(react@19.2.7) + '@radix-ui/react-dismissable-layer': 1.1.13(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + '@radix-ui/react-focus-guards': 1.1.4(@types/react@19.2.17)(react@19.2.7) + '@radix-ui/react-focus-scope': 1.1.10(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + '@radix-ui/react-id': 1.1.2(@types/react@19.2.17)(react@19.2.7) + '@radix-ui/react-popper': 1.3.1(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + '@radix-ui/react-portal': 1.1.12(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + '@radix-ui/react-presence': 1.1.6(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + '@radix-ui/react-primitive': 2.1.6(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + '@radix-ui/react-slot': 1.3.0(@types/react@19.2.17)(react@19.2.7) + '@radix-ui/react-use-callback-ref': 1.1.2(@types/react@19.2.17)(react@19.2.7) + '@radix-ui/react-use-controllable-state': 1.2.3(@types/react@19.2.17)(react@19.2.7) + '@radix-ui/react-use-layout-effect': 1.1.2(@types/react@19.2.17)(react@19.2.7) + '@radix-ui/react-use-previous': 1.1.2(@types/react@19.2.17)(react@19.2.7) + '@radix-ui/react-visually-hidden': 1.2.6(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + aria-hidden: 1.2.6 + react: 19.2.7 + react-dom: 19.2.7(react@19.2.7) + react-remove-scroll: 2.7.2(@types/react@19.2.17)(react@19.2.7) + optionalDependencies: + '@types/react': 19.2.17 + '@types/react-dom': 19.2.3(@types/react@19.2.17) - '@oven/bun-windows-x64-baseline@1.3.11': - optional: true + '@radix-ui/react-separator@1.1.10(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)': + dependencies: + '@radix-ui/react-primitive': 2.1.6(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + react: 19.2.7 + react-dom: 19.2.7(react@19.2.7) + optionalDependencies: + '@types/react': 19.2.17 + '@types/react-dom': 19.2.3(@types/react@19.2.17) - '@oven/bun-windows-x64@1.3.11': - optional: true + '@radix-ui/react-slider@1.4.1(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)': + dependencies: + '@radix-ui/number': 1.1.2 + '@radix-ui/primitive': 1.1.4 + '@radix-ui/react-collection': 1.1.10(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + '@radix-ui/react-compose-refs': 1.1.3(@types/react@19.2.17)(react@19.2.7) + '@radix-ui/react-context': 1.1.4(@types/react@19.2.17)(react@19.2.7) + '@radix-ui/react-direction': 1.1.2(@types/react@19.2.17)(react@19.2.7) + '@radix-ui/react-primitive': 2.1.6(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + '@radix-ui/react-use-controllable-state': 1.2.3(@types/react@19.2.17)(react@19.2.7) + '@radix-ui/react-use-layout-effect': 1.1.2(@types/react@19.2.17)(react@19.2.7) + '@radix-ui/react-use-previous': 1.1.2(@types/react@19.2.17)(react@19.2.7) + '@radix-ui/react-use-size': 1.1.2(@types/react@19.2.17)(react@19.2.7) + react: 19.2.7 + react-dom: 19.2.7(react@19.2.7) + optionalDependencies: + '@types/react': 19.2.17 + '@types/react-dom': 19.2.3(@types/react@19.2.17) - '@pagefind/darwin-arm64@1.5.2': - optional: true + '@radix-ui/react-slot@1.3.0(@types/react@19.2.17)(react@19.2.7)': + dependencies: + '@radix-ui/react-compose-refs': 1.1.3(@types/react@19.2.17)(react@19.2.7) + react: 19.2.7 + optionalDependencies: + '@types/react': 19.2.17 - '@pagefind/darwin-x64@1.5.2': - optional: true + '@radix-ui/react-switch@1.3.1(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)': + dependencies: + '@radix-ui/primitive': 1.1.4 + '@radix-ui/react-compose-refs': 1.1.3(@types/react@19.2.17)(react@19.2.7) + '@radix-ui/react-context': 1.1.4(@types/react@19.2.17)(react@19.2.7) + '@radix-ui/react-primitive': 2.1.6(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + '@radix-ui/react-use-controllable-state': 1.2.3(@types/react@19.2.17)(react@19.2.7) + '@radix-ui/react-use-previous': 1.1.2(@types/react@19.2.17)(react@19.2.7) + '@radix-ui/react-use-size': 1.1.2(@types/react@19.2.17)(react@19.2.7) + react: 19.2.7 + react-dom: 19.2.7(react@19.2.7) + optionalDependencies: + '@types/react': 19.2.17 + '@types/react-dom': 19.2.3(@types/react@19.2.17) - '@pagefind/default-ui@1.5.2': {} + '@radix-ui/react-tabs@1.1.15(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)': + dependencies: + '@radix-ui/primitive': 1.1.4 + '@radix-ui/react-context': 1.1.4(@types/react@19.2.17)(react@19.2.7) + '@radix-ui/react-direction': 1.1.2(@types/react@19.2.17)(react@19.2.7) + '@radix-ui/react-id': 1.1.2(@types/react@19.2.17)(react@19.2.7) + '@radix-ui/react-presence': 1.1.6(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + '@radix-ui/react-primitive': 2.1.6(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + '@radix-ui/react-roving-focus': 1.1.13(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + '@radix-ui/react-use-controllable-state': 1.2.3(@types/react@19.2.17)(react@19.2.7) + react: 19.2.7 + react-dom: 19.2.7(react@19.2.7) + optionalDependencies: + '@types/react': 19.2.17 + '@types/react-dom': 19.2.3(@types/react@19.2.17) - '@pagefind/freebsd-x64@1.5.2': - optional: true + '@radix-ui/react-toggle-group@1.1.13(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)': + dependencies: + '@radix-ui/primitive': 1.1.4 + '@radix-ui/react-context': 1.1.4(@types/react@19.2.17)(react@19.2.7) + '@radix-ui/react-direction': 1.1.2(@types/react@19.2.17)(react@19.2.7) + '@radix-ui/react-primitive': 2.1.6(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + '@radix-ui/react-roving-focus': 1.1.13(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + '@radix-ui/react-toggle': 1.1.12(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + '@radix-ui/react-use-controllable-state': 1.2.3(@types/react@19.2.17)(react@19.2.7) + react: 19.2.7 + react-dom: 19.2.7(react@19.2.7) + optionalDependencies: + '@types/react': 19.2.17 + '@types/react-dom': 19.2.3(@types/react@19.2.17) - '@pagefind/linux-arm64@1.5.2': - optional: true + '@radix-ui/react-toggle@1.1.12(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)': + dependencies: + '@radix-ui/primitive': 1.1.4 + '@radix-ui/react-primitive': 2.1.6(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + '@radix-ui/react-use-controllable-state': 1.2.3(@types/react@19.2.17)(react@19.2.7) + react: 19.2.7 + react-dom: 19.2.7(react@19.2.7) + optionalDependencies: + '@types/react': 19.2.17 + '@types/react-dom': 19.2.3(@types/react@19.2.17) - '@pagefind/linux-x64@1.5.2': - optional: true + '@radix-ui/react-tooltip@1.2.10(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)': + dependencies: + '@radix-ui/primitive': 1.1.4 + '@radix-ui/react-compose-refs': 1.1.3(@types/react@19.2.17)(react@19.2.7) + '@radix-ui/react-context': 1.1.4(@types/react@19.2.17)(react@19.2.7) + '@radix-ui/react-dismissable-layer': 1.1.13(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + '@radix-ui/react-id': 1.1.2(@types/react@19.2.17)(react@19.2.7) + '@radix-ui/react-popper': 1.3.1(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + '@radix-ui/react-portal': 1.1.12(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + '@radix-ui/react-presence': 1.1.6(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + '@radix-ui/react-primitive': 2.1.6(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + '@radix-ui/react-slot': 1.3.0(@types/react@19.2.17)(react@19.2.7) + '@radix-ui/react-use-controllable-state': 1.2.3(@types/react@19.2.17)(react@19.2.7) + '@radix-ui/react-visually-hidden': 1.2.6(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + react: 19.2.7 + react-dom: 19.2.7(react@19.2.7) + optionalDependencies: + '@types/react': 19.2.17 + '@types/react-dom': 19.2.3(@types/react@19.2.17) - '@pagefind/windows-arm64@1.5.2': - optional: true + '@radix-ui/react-use-callback-ref@1.1.2(@types/react@19.2.17)(react@19.2.7)': + dependencies: + react: 19.2.7 + optionalDependencies: + '@types/react': 19.2.17 - '@pagefind/windows-x64@1.5.2': - optional: true + '@radix-ui/react-use-controllable-state@1.2.3(@types/react@19.2.17)(react@19.2.7)': + dependencies: + '@radix-ui/react-use-effect-event': 0.0.3(@types/react@19.2.17)(react@19.2.7) + '@radix-ui/react-use-layout-effect': 1.1.2(@types/react@19.2.17)(react@19.2.7) + react: 19.2.7 + optionalDependencies: + '@types/react': 19.2.17 - '@pkgjs/parseargs@0.11.0': - optional: true + '@radix-ui/react-use-effect-event@0.0.3(@types/react@19.2.17)(react@19.2.7)': + dependencies: + '@radix-ui/react-use-layout-effect': 1.1.2(@types/react@19.2.17)(react@19.2.7) + react: 19.2.7 + optionalDependencies: + '@types/react': 19.2.17 - '@playwright/test@1.59.1': + '@radix-ui/react-use-escape-keydown@1.1.2(@types/react@19.2.17)(react@19.2.7)': dependencies: - playwright: 1.59.1 + '@radix-ui/react-use-callback-ref': 1.1.2(@types/react@19.2.17)(react@19.2.7) + react: 19.2.7 + optionalDependencies: + '@types/react': 19.2.17 - '@protobufjs/aspromise@1.1.2': {} + '@radix-ui/react-use-is-hydrated@0.1.1(@types/react@19.2.17)(react@19.2.7)': + dependencies: + react: 19.2.7 + optionalDependencies: + '@types/react': 19.2.17 - '@protobufjs/base64@1.1.2': {} + '@radix-ui/react-use-layout-effect@1.1.2(@types/react@19.2.17)(react@19.2.7)': + dependencies: + react: 19.2.7 + optionalDependencies: + '@types/react': 19.2.17 - '@protobufjs/codegen@2.0.4': {} + '@radix-ui/react-use-previous@1.1.2(@types/react@19.2.17)(react@19.2.7)': + dependencies: + react: 19.2.7 + optionalDependencies: + '@types/react': 19.2.17 - '@protobufjs/eventemitter@1.1.0': {} + '@radix-ui/react-use-rect@1.1.2(@types/react@19.2.17)(react@19.2.7)': + dependencies: + '@radix-ui/rect': 1.1.2 + react: 19.2.7 + optionalDependencies: + '@types/react': 19.2.17 - '@protobufjs/fetch@1.1.0': + '@radix-ui/react-use-size@1.1.2(@types/react@19.2.17)(react@19.2.7)': dependencies: - '@protobufjs/aspromise': 1.1.2 - '@protobufjs/inquire': 1.1.0 + '@radix-ui/react-use-layout-effect': 1.1.2(@types/react@19.2.17)(react@19.2.7) + react: 19.2.7 + optionalDependencies: + '@types/react': 19.2.17 - '@protobufjs/float@1.0.2': {} + '@radix-ui/react-visually-hidden@1.2.6(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)': + dependencies: + '@radix-ui/react-primitive': 2.1.6(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + react: 19.2.7 + react-dom: 19.2.7(react@19.2.7) + optionalDependencies: + '@types/react': 19.2.17 + '@types/react-dom': 19.2.3(@types/react@19.2.17) - '@protobufjs/inquire@1.1.0': {} + '@radix-ui/rect@1.1.2': {} - '@protobufjs/path@1.1.2': {} + '@react-aria/focus@3.22.1(react-dom@19.2.7(react@19.2.7))(react@19.2.7)': + dependencies: + '@swc/helpers': 0.5.23 + react: 19.2.7 + react-aria: 3.50.0(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + react-dom: 19.2.7(react@19.2.7) - '@protobufjs/pool@1.1.0': {} + '@react-aria/interactions@3.28.1(react-dom@19.2.7(react@19.2.7))(react@19.2.7)': + dependencies: + '@react-types/shared': 3.36.0(react@19.2.7) + '@swc/helpers': 0.5.23 + react: 19.2.7 + react-aria: 3.50.0(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + react-dom: 19.2.7(react@19.2.7) - '@protobufjs/utf8@1.1.0': {} + '@react-types/shared@3.36.0(react@19.2.7)': + dependencies: + react: 19.2.7 - '@rivet-dev/docs-theme@https://codeload.github.com/rivet-dev/docs-theme/tar.gz/ed588a45112cfe70c9abe6e8f52e8fe47a1d6162(@astrojs/starlight@0.36.3(astro@5.18.2(@types/node@24.13.2)(jiti@1.21.7)(rollup@4.60.1)(tsx@4.21.0)(typescript@5.9.3)(yaml@2.9.0)))(astro@5.18.2(@types/node@24.13.2)(jiti@1.21.7)(rollup@4.60.1)(tsx@4.21.0)(typescript@5.9.3)(yaml@2.9.0))': + '@rivet-dev/docs-theme@file:website/vendor/theme(@babel/core@7.29.7)(@babel/runtime@7.29.7)(@babel/template@7.29.7)(@codemirror/language@6.12.4)(@codemirror/search@6.7.1)(@codemirror/theme-one-dark@6.1.3)(@types/node@24.13.2)(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(astro@5.18.2(@types/node@24.13.2)(jiti@1.21.7)(rollup@4.60.1)(tsx@4.21.0)(typescript@5.9.3)(yaml@2.9.0))(codemirror@6.0.2)(jiti@1.21.7)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)(tsx@4.21.0)(use-sync-external-store@1.6.0(react@19.2.7))(yaml@2.9.0)': dependencies: - '@astrojs/starlight': 0.36.3(astro@5.18.2(@types/node@24.13.2)(jiti@1.21.7)(rollup@4.60.1)(tsx@4.21.0)(typescript@5.9.3)(yaml@2.9.0)) + '@astrojs/mdx': 4.3.14(astro@5.18.2(@types/node@24.13.2)(jiti@1.21.7)(rollup@4.60.1)(tsx@4.21.0)(typescript@5.9.3)(yaml@2.9.0)) + '@astrojs/react': 4.4.2(@types/node@24.13.2)(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(jiti@1.21.7)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)(tsx@4.21.0)(yaml@2.9.0) + '@astrojs/sitemap': 3.7.3 + '@fortawesome/fontawesome-svg-core': 7.3.0 + '@fortawesome/free-brands-svg-icons': 7.3.0 + '@fortawesome/free-solid-svg-icons': 7.3.0 + '@fortawesome/react-fontawesome': 3.3.1(@fortawesome/fontawesome-svg-core@7.3.0)(react@19.2.7) + '@headlessui/react': 2.2.10(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + '@rivet-gg/components': file:website/vendor/theme/vendor/components(@babel/core@7.29.7)(@babel/runtime@7.29.7)(@babel/template@7.29.7)(@codemirror/language@6.12.4)(@codemirror/search@6.7.1)(@codemirror/theme-one-dark@6.1.3)(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(codemirror@6.0.2)(lodash@4.18.1)(posthog-js@1.395.0)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)(tailwindcss@3.4.19(tsx@4.21.0)(yaml@2.9.0)) + '@rivet-gg/icons': file:website/vendor/theme/vendor/icons(@fortawesome/fontawesome-svg-core@7.3.0)(@fortawesome/free-brands-svg-icons@7.3.0)(@fortawesome/free-solid-svg-icons@7.3.0)(@fortawesome/react-fontawesome@3.3.1(@fortawesome/fontawesome-svg-core@7.3.0)(react@19.2.7))(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + '@shikijs/transformers': 3.23.0 + '@sindresorhus/slugify': 3.0.0 + '@tailwindcss/typography': 0.5.20(tailwindcss@3.4.19(tsx@4.21.0)(yaml@2.9.0)) + acorn: 8.17.0 astro: 5.18.2(@types/node@24.13.2)(jiti@1.21.7)(rollup@4.60.1)(tsx@4.21.0)(typescript@5.9.3)(yaml@2.9.0) + clsx: 2.1.1 + dedent: 1.7.2 + esast-util-from-js: 2.0.1 + escape-html: 1.0.3 + estree-util-to-js: 2.0.0 + fast-glob: 3.3.3 + framer-motion: 12.40.0(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + fuse.js: 7.4.2 + lodash: 4.18.1 + lucide-react: 0.439.0(react@19.2.7) + mdast-util-to-string: 4.0.0 + mdx-annotations: 0.1.4 + mermaid: 11.16.0 + playwright: 1.59.1 + posthog-js: 1.395.0 + react: 19.2.7 + react-dom: 19.2.7(react@19.2.7) + react-markdown: 10.1.0(@types/react@19.2.17)(react@19.2.7) + rehype-mermaid: 3.0.0(playwright@1.59.1) + rehype-parse: 9.0.1 + remark-gfm: 4.0.1 + shiki: 3.23.0 + tailwindcss: 3.4.19(tsx@4.21.0)(yaml@2.9.0) + tm-themes: 1.12.2 + typesense: 2.1.0(@babel/runtime@7.29.7) + unified: 11.0.5 + unist-util-filter: 5.0.1 + unist-util-visit: 5.1.0 + zustand: 5.0.14(@types/react@19.2.17)(react@19.2.7)(use-sync-external-store@1.6.0(react@19.2.7)) + transitivePeerDependencies: + - '@babel/core' + - '@babel/runtime' + - '@babel/template' + - '@codemirror/language' + - '@codemirror/search' + - '@codemirror/theme-one-dark' + - '@emotion/is-prop-valid' + - '@types/node' + - '@types/react' + - '@types/react-dom' + - babel-plugin-macros + - codemirror + - debug + - immer + - jiti + - less + - lightningcss + - sass + - sass-embedded + - stylus + - sugarss + - supports-color + - terser + - tsx + - use-sync-external-store + - yaml + + '@rivet-gg/components@file:website/vendor/theme/vendor/components(@babel/core@7.29.7)(@babel/runtime@7.29.7)(@babel/template@7.29.7)(@codemirror/language@6.12.4)(@codemirror/search@6.7.1)(@codemirror/theme-one-dark@6.1.3)(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(codemirror@6.0.2)(lodash@4.18.1)(posthog-js@1.395.0)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)(tailwindcss@3.4.19(tsx@4.21.0)(yaml@2.9.0))': + dependencies: + '@codemirror/autocomplete': 6.20.3 + '@codemirror/commands': 6.10.4 + '@codemirror/lang-javascript': 6.2.5 + '@codemirror/lang-json': 6.0.2 + '@codemirror/lint': 6.9.7 + '@codemirror/state': 6.7.0 + '@codemirror/view': 6.43.4 + '@fortawesome/fontawesome-svg-core': 6.7.2 + '@fortawesome/free-brands-svg-icons': 6.7.2 + '@fortawesome/free-solid-svg-icons': 6.7.2 + '@fortawesome/react-fontawesome': 0.2.6(@fortawesome/fontawesome-svg-core@6.7.2)(react@19.2.7) + '@hookform/resolvers': 3.10.0(react-hook-form@7.80.0(react@19.2.7)) + '@radix-ui/react-accordion': 1.2.14(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + '@radix-ui/react-avatar': 1.2.0(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + '@radix-ui/react-checkbox': 1.3.5(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + '@radix-ui/react-context-menu': 2.3.1(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + '@radix-ui/react-dialog': 1.1.17(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + '@radix-ui/react-dropdown-menu': 2.1.18(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + '@radix-ui/react-label': 2.1.10(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + '@radix-ui/react-popover': 1.1.17(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + '@radix-ui/react-progress': 1.1.10(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + '@radix-ui/react-radio-group': 1.4.1(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + '@radix-ui/react-scroll-area': 1.2.12(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + '@radix-ui/react-select': 2.3.1(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + '@radix-ui/react-separator': 1.1.10(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + '@radix-ui/react-slider': 1.4.1(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + '@radix-ui/react-slot': 1.3.0(@types/react@19.2.17)(react@19.2.7) + '@radix-ui/react-switch': 1.3.1(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + '@radix-ui/react-tabs': 1.1.15(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + '@radix-ui/react-toggle': 1.1.12(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + '@radix-ui/react-toggle-group': 1.1.13(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + '@radix-ui/react-tooltip': 1.2.10(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + '@radix-ui/react-visually-hidden': 1.2.6(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + '@rivet-gg/icons': file:website/vendor/theme/vendor/icons(@fortawesome/fontawesome-svg-core@6.7.2)(@fortawesome/free-brands-svg-icons@6.7.2)(@fortawesome/free-solid-svg-icons@6.7.2)(@fortawesome/react-fontawesome@0.2.6(@fortawesome/fontawesome-svg-core@6.7.2)(react@19.2.7))(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + '@sentry/react': 8.55.2(react@19.2.7) + '@shikijs/langs': 3.23.0 + '@tailwindcss/container-queries': 0.1.1(tailwindcss@3.4.19(tsx@4.21.0)(yaml@2.9.0)) + '@tailwindcss/typography': 0.5.20(tailwindcss@3.4.19(tsx@4.21.0)(yaml@2.9.0)) + '@tanstack/react-table': 8.21.3(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + '@tanstack/react-virtual': 3.14.4(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + '@uiw/codemirror-extensions-basic-setup': 4.25.10(@codemirror/autocomplete@6.20.3)(@codemirror/commands@6.10.4)(@codemirror/language@6.12.4)(@codemirror/lint@6.9.7)(@codemirror/search@6.7.1)(@codemirror/state@6.7.0)(@codemirror/view@6.43.4) + '@uiw/codemirror-theme-github': 4.25.10(@codemirror/language@6.12.4)(@codemirror/state@6.7.0)(@codemirror/view@6.43.4) + '@uiw/react-codemirror': 4.25.10(@babel/runtime@7.29.7)(@codemirror/autocomplete@6.20.3)(@codemirror/language@6.12.4)(@codemirror/lint@6.9.7)(@codemirror/search@6.7.1)(@codemirror/state@6.7.0)(@codemirror/theme-one-dark@6.1.3)(@codemirror/view@6.43.4)(codemirror@6.0.2)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + class-variance-authority: 0.7.1 + clsx: 2.1.1 + cmdk: 1.1.1(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + date-fns: 4.4.0 + esast-util-from-js: 2.0.1 + estree-util-to-js: 2.0.0 + fast-deep-equal: 3.1.3 + framer-motion: 11.18.2(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + input-otp: 1.4.2(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + jotai: 2.20.1(@babel/core@7.29.7)(@babel/template@7.29.7)(@types/react@19.2.17)(react@19.2.7) + jotai-effect: 2.3.1(jotai@2.20.1(@babel/core@7.29.7)(@babel/template@7.29.7)(@types/react@19.2.17)(react@19.2.7)) + lodash: 4.18.1 + lucide-react: 0.439.0(react@19.2.7) + react: 19.2.7 + react-day-picker: 8.10.1(date-fns@4.4.0)(react@19.2.7) + react-dom: 19.2.7(react@19.2.7) + react-hook-form: 7.80.0(react@19.2.7) + react-resizable-panels: 2.1.9(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + recharts: 2.15.4(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + sonner: 1.7.4(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + tailwind-merge: 2.6.1 + tailwindcss-animate: 1.0.7(tailwindcss@3.4.19(tsx@4.21.0)(yaml@2.9.0)) + usehooks-ts: 3.1.1(react@19.2.7) + zod: 3.25.76 + optionalDependencies: + posthog-js: 1.395.0 + transitivePeerDependencies: + - '@babel/core' + - '@babel/runtime' + - '@babel/template' + - '@codemirror/language' + - '@codemirror/search' + - '@codemirror/theme-one-dark' + - '@emotion/is-prop-valid' + - '@types/react' + - '@types/react-dom' + - codemirror + - tailwindcss + + '@rivet-gg/icons@file:website/vendor/theme/vendor/icons(@fortawesome/fontawesome-svg-core@6.7.2)(@fortawesome/free-brands-svg-icons@6.7.2)(@fortawesome/free-solid-svg-icons@6.7.2)(@fortawesome/react-fontawesome@0.2.6(@fortawesome/fontawesome-svg-core@6.7.2)(react@19.2.7))(react-dom@19.2.7(react@19.2.7))(react@19.2.7)': + dependencies: + '@fortawesome/fontawesome-svg-core': 6.7.2 + '@fortawesome/free-brands-svg-icons': 6.7.2 + '@fortawesome/free-solid-svg-icons': 6.7.2 + '@fortawesome/react-fontawesome': 0.2.6(@fortawesome/fontawesome-svg-core@6.7.2)(react@19.2.7) + react: 19.2.7 + react-dom: 19.2.7(react@19.2.7) + + '@rivet-gg/icons@file:website/vendor/theme/vendor/icons(@fortawesome/fontawesome-svg-core@7.3.0)(@fortawesome/free-brands-svg-icons@7.3.0)(@fortawesome/free-solid-svg-icons@7.3.0)(@fortawesome/react-fontawesome@3.3.1(@fortawesome/fontawesome-svg-core@7.3.0)(react@19.2.7))(react-dom@19.2.7(react@19.2.7))(react@19.2.7)': + dependencies: + '@fortawesome/fontawesome-svg-core': 7.3.0 + '@fortawesome/free-brands-svg-icons': 7.3.0 + '@fortawesome/free-solid-svg-icons': 7.3.0 + '@fortawesome/react-fontawesome': 3.3.1(@fortawesome/fontawesome-svg-core@7.3.0)(react@19.2.7) + react: 19.2.7 + react-dom: 19.2.7(react@19.2.7) '@rivetkit/bare-ts@0.6.2': {} @@ -7425,6 +9823,41 @@ snapshots: '@sandbox-agent/cli-win32-x64': 0.4.2 optional: true + '@sentry-internal/browser-utils@8.55.2': + dependencies: + '@sentry/core': 8.55.2 + + '@sentry-internal/feedback@8.55.2': + dependencies: + '@sentry/core': 8.55.2 + + '@sentry-internal/replay-canvas@8.55.2': + dependencies: + '@sentry-internal/replay': 8.55.2 + '@sentry/core': 8.55.2 + + '@sentry-internal/replay@8.55.2': + dependencies: + '@sentry-internal/browser-utils': 8.55.2 + '@sentry/core': 8.55.2 + + '@sentry/browser@8.55.2': + dependencies: + '@sentry-internal/browser-utils': 8.55.2 + '@sentry-internal/feedback': 8.55.2 + '@sentry-internal/replay': 8.55.2 + '@sentry-internal/replay-canvas': 8.55.2 + '@sentry/core': 8.55.2 + + '@sentry/core@8.55.2': {} + + '@sentry/react@8.55.2(react@19.2.7)': + dependencies: + '@sentry/browser': 8.55.2 + '@sentry/core': 8.55.2 + hoist-non-react-statics: 3.3.2 + react: 19.2.7 + '@shikijs/core@3.23.0': dependencies: '@shikijs/types': 3.23.0 @@ -7451,6 +9884,11 @@ snapshots: dependencies: '@shikijs/types': 3.23.0 + '@shikijs/transformers@3.23.0': + dependencies: + '@shikijs/core': 3.23.0 + '@shikijs/types': 3.23.0 + '@shikijs/types@3.23.0': dependencies: '@shikijs/vscode-textmate': 10.0.2 @@ -7462,6 +9900,13 @@ snapshots: '@sinclair/typebox@0.34.49': {} + '@sindresorhus/slugify@3.0.0': + dependencies: + '@sindresorhus/transliterate': 2.3.1 + escape-string-regexp: 5.0.0 + + '@sindresorhus/transliterate@2.3.1': {} + '@smithy/core@3.26.0': dependencies: '@aws-crypto/crc32': 5.2.0 @@ -7510,6 +9955,35 @@ snapshots: '@smithy/util-buffer-from': 2.2.0 tslib: 2.8.1 + '@swc/helpers@0.5.23': + dependencies: + tslib: 2.8.1 + + '@tailwindcss/container-queries@0.1.1(tailwindcss@3.4.19(tsx@4.21.0)(yaml@2.9.0))': + dependencies: + tailwindcss: 3.4.19(tsx@4.21.0)(yaml@2.9.0) + + '@tailwindcss/typography@0.5.20(tailwindcss@3.4.19(tsx@4.21.0)(yaml@2.9.0))': + dependencies: + postcss-selector-parser: 6.0.10 + tailwindcss: 3.4.19(tsx@4.21.0)(yaml@2.9.0) + + '@tanstack/react-table@8.21.3(react-dom@19.2.7(react@19.2.7))(react@19.2.7)': + dependencies: + '@tanstack/table-core': 8.21.3 + react: 19.2.7 + react-dom: 19.2.7(react@19.2.7) + + '@tanstack/react-virtual@3.14.4(react-dom@19.2.7(react@19.2.7))(react@19.2.7)': + dependencies: + '@tanstack/virtual-core': 3.17.2 + react: 19.2.7 + react-dom: 19.2.7(react@19.2.7) + + '@tanstack/table-core@8.21.3': {} + + '@tanstack/virtual-core@3.17.2': {} + '@tokenizer/inflate@0.4.1': dependencies: debug: 4.4.3 @@ -7560,6 +10034,123 @@ snapshots: dependencies: '@babel/types': 7.29.7 + '@types/d3-array@3.2.2': {} + + '@types/d3-axis@3.0.6': + dependencies: + '@types/d3-selection': 3.0.11 + + '@types/d3-brush@3.0.6': + dependencies: + '@types/d3-selection': 3.0.11 + + '@types/d3-chord@3.0.6': {} + + '@types/d3-color@3.1.3': {} + + '@types/d3-contour@3.0.6': + dependencies: + '@types/d3-array': 3.2.2 + '@types/geojson': 7946.0.16 + + '@types/d3-delaunay@6.0.4': {} + + '@types/d3-dispatch@3.0.7': {} + + '@types/d3-drag@3.0.7': + dependencies: + '@types/d3-selection': 3.0.11 + + '@types/d3-dsv@3.0.7': {} + + '@types/d3-ease@3.0.2': {} + + '@types/d3-fetch@3.0.7': + dependencies: + '@types/d3-dsv': 3.0.7 + + '@types/d3-force@3.0.10': {} + + '@types/d3-format@3.0.4': {} + + '@types/d3-geo@3.1.0': + dependencies: + '@types/geojson': 7946.0.16 + + '@types/d3-hierarchy@3.1.7': {} + + '@types/d3-interpolate@3.0.4': + dependencies: + '@types/d3-color': 3.1.3 + + '@types/d3-path@3.1.1': {} + + '@types/d3-polygon@3.0.2': {} + + '@types/d3-quadtree@3.0.6': {} + + '@types/d3-random@3.0.3': {} + + '@types/d3-scale-chromatic@3.1.0': {} + + '@types/d3-scale@4.0.9': + dependencies: + '@types/d3-time': 3.0.4 + + '@types/d3-selection@3.0.11': {} + + '@types/d3-shape@3.1.8': + dependencies: + '@types/d3-path': 3.1.1 + + '@types/d3-time-format@4.0.3': {} + + '@types/d3-time@3.0.4': {} + + '@types/d3-timer@3.0.2': {} + + '@types/d3-transition@3.0.9': + dependencies: + '@types/d3-selection': 3.0.11 + + '@types/d3-zoom@3.0.8': + dependencies: + '@types/d3-interpolate': 3.0.4 + '@types/d3-selection': 3.0.11 + + '@types/d3@7.4.3': + dependencies: + '@types/d3-array': 3.2.2 + '@types/d3-axis': 3.0.6 + '@types/d3-brush': 3.0.6 + '@types/d3-chord': 3.0.6 + '@types/d3-color': 3.1.3 + '@types/d3-contour': 3.0.6 + '@types/d3-delaunay': 6.0.4 + '@types/d3-dispatch': 3.0.7 + '@types/d3-drag': 3.0.7 + '@types/d3-dsv': 3.0.7 + '@types/d3-ease': 3.0.2 + '@types/d3-fetch': 3.0.7 + '@types/d3-force': 3.0.10 + '@types/d3-format': 3.0.4 + '@types/d3-geo': 3.1.0 + '@types/d3-hierarchy': 3.1.7 + '@types/d3-interpolate': 3.0.4 + '@types/d3-path': 3.1.1 + '@types/d3-polygon': 3.0.2 + '@types/d3-quadtree': 3.0.6 + '@types/d3-random': 3.0.3 + '@types/d3-scale': 4.0.9 + '@types/d3-scale-chromatic': 3.1.0 + '@types/d3-selection': 3.0.11 + '@types/d3-shape': 3.1.8 + '@types/d3-time': 3.0.4 + '@types/d3-time-format': 4.0.3 + '@types/d3-timer': 3.0.2 + '@types/d3-transition': 3.0.9 + '@types/d3-zoom': 3.0.8 + '@types/debug@4.1.13': dependencies: '@types/ms': 2.1.0 @@ -7570,12 +10161,12 @@ snapshots: '@types/estree@1.0.8': {} + '@types/geojson@7946.0.16': {} + '@types/hast@3.0.4': dependencies: '@types/unist': 3.0.3 - '@types/js-yaml@4.0.9': {} - '@types/mdast@4.0.4': dependencies: '@types/unist': 3.0.3 @@ -7614,6 +10205,9 @@ snapshots: '@types/semver@7.7.1': {} + '@types/trusted-types@2.0.7': + optional: true + '@types/unist@2.0.11': {} '@types/unist@3.0.3': {} @@ -7623,8 +10217,54 @@ snapshots: '@types/node': 22.19.15 optional: true + '@uiw/codemirror-extensions-basic-setup@4.25.10(@codemirror/autocomplete@6.20.3)(@codemirror/commands@6.10.4)(@codemirror/language@6.12.4)(@codemirror/lint@6.9.7)(@codemirror/search@6.7.1)(@codemirror/state@6.7.0)(@codemirror/view@6.43.4)': + dependencies: + '@codemirror/autocomplete': 6.20.3 + '@codemirror/commands': 6.10.4 + '@codemirror/language': 6.12.4 + '@codemirror/lint': 6.9.7 + '@codemirror/search': 6.7.1 + '@codemirror/state': 6.7.0 + '@codemirror/view': 6.43.4 + + '@uiw/codemirror-theme-github@4.25.10(@codemirror/language@6.12.4)(@codemirror/state@6.7.0)(@codemirror/view@6.43.4)': + dependencies: + '@uiw/codemirror-themes': 4.25.10(@codemirror/language@6.12.4)(@codemirror/state@6.7.0)(@codemirror/view@6.43.4) + transitivePeerDependencies: + - '@codemirror/language' + - '@codemirror/state' + - '@codemirror/view' + + '@uiw/codemirror-themes@4.25.10(@codemirror/language@6.12.4)(@codemirror/state@6.7.0)(@codemirror/view@6.43.4)': + dependencies: + '@codemirror/language': 6.12.4 + '@codemirror/state': 6.7.0 + '@codemirror/view': 6.43.4 + + '@uiw/react-codemirror@4.25.10(@babel/runtime@7.29.7)(@codemirror/autocomplete@6.20.3)(@codemirror/language@6.12.4)(@codemirror/lint@6.9.7)(@codemirror/search@6.7.1)(@codemirror/state@6.7.0)(@codemirror/theme-one-dark@6.1.3)(@codemirror/view@6.43.4)(codemirror@6.0.2)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)': + dependencies: + '@babel/runtime': 7.29.7 + '@codemirror/commands': 6.10.4 + '@codemirror/state': 6.7.0 + '@codemirror/theme-one-dark': 6.1.3 + '@codemirror/view': 6.43.4 + '@uiw/codemirror-extensions-basic-setup': 4.25.10(@codemirror/autocomplete@6.20.3)(@codemirror/commands@6.10.4)(@codemirror/language@6.12.4)(@codemirror/lint@6.9.7)(@codemirror/search@6.7.1)(@codemirror/state@6.7.0)(@codemirror/view@6.43.4) + codemirror: 6.0.2 + react: 19.2.7 + react-dom: 19.2.7(react@19.2.7) + transitivePeerDependencies: + - '@codemirror/autocomplete' + - '@codemirror/language' + - '@codemirror/lint' + - '@codemirror/search' + '@ungap/structured-clone@1.3.1': {} + '@upsetjs/venn.js@2.0.0': + optionalDependencies: + d3-selection: 3.0.0 + d3-transition: 3.0.1(d3-selection@3.0.0) + '@vitejs/plugin-react@4.7.0(vite@6.4.3(@types/node@24.13.2)(jiti@1.21.7)(tsx@4.21.0)(yaml@2.9.0))': dependencies: '@babel/core': 7.29.7 @@ -7694,6 +10334,12 @@ snapshots: transitivePeerDependencies: - zod + agent-base@6.0.2: + dependencies: + debug: 4.4.3 + transitivePeerDependencies: + - supports-color + agent-base@7.1.4: {} ajv-formats@3.0.1(ajv@8.20.0): @@ -7732,6 +10378,10 @@ snapshots: argparse@2.0.1: {} + aria-hidden@1.2.6: + dependencies: + tslib: 2.8.1 + aria-query@5.3.2: {} array-iterate@2.0.1: {} @@ -7763,11 +10413,6 @@ snapshots: astring@1.9.0: {} - astro-expressive-code@0.41.7(astro@5.18.2(@types/node@24.13.2)(jiti@1.21.7)(rollup@4.60.1)(tsx@4.21.0)(typescript@5.9.3)(yaml@2.9.0)): - dependencies: - astro: 5.18.2(@types/node@24.13.2)(jiti@1.21.7)(rollup@4.60.1)(tsx@4.21.0)(typescript@5.9.3)(yaml@2.9.0) - rehype-expressive-code: 0.41.7 - astro@5.18.2(@types/node@24.13.2)(jiti@1.21.7)(rollup@4.60.1)(tsx@4.21.0)(typescript@5.9.3)(yaml@2.9.0): dependencies: '@astrojs/compiler': 2.13.1 @@ -7870,6 +10515,8 @@ snapshots: - uploadthing - yaml + asynckit@0.4.0: {} + autoprefixer@10.5.0(postcss@8.5.8): dependencies: browserslist: 4.28.2 @@ -7883,6 +10530,16 @@ snapshots: dependencies: possible-typed-array-names: 1.1.0 + axios@1.18.1: + dependencies: + follow-redirects: 1.16.0 + form-data: 4.0.6 + https-proxy-agent: 5.0.1 + proxy-from-env: 2.1.0 + transitivePeerDependencies: + - debug + - supports-color + axobject-query@4.1.0: {} bail@2.0.2: {} @@ -7899,14 +10556,6 @@ snapshots: basic-ftp@5.3.1: {} - bcp-47-match@2.0.3: {} - - bcp-47@2.1.0: - dependencies: - is-alphabetical: 2.0.1 - is-alphanumerical: 2.0.1 - is-decimal: 2.0.1 - bcrypt-pbkdf@1.0.2: dependencies: tweetnacl: 0.14.5 @@ -8138,6 +10787,10 @@ snapshots: safe-buffer: 5.2.1 to-buffer: 1.2.2 + class-variance-authority@0.7.1: + dependencies: + clsx: 2.1.1 + cli-boxes@3.0.0: {} cli-highlight@2.1.11: @@ -8164,6 +10817,28 @@ snapshots: clsx@2.1.1: {} + cmdk@1.1.1(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7): + dependencies: + '@radix-ui/react-compose-refs': 1.1.3(@types/react@19.2.17)(react@19.2.7) + '@radix-ui/react-dialog': 1.1.17(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + '@radix-ui/react-id': 1.1.2(@types/react@19.2.17)(react@19.2.7) + '@radix-ui/react-primitive': 2.1.6(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + react: 19.2.7 + react-dom: 19.2.7(react@19.2.7) + transitivePeerDependencies: + - '@types/react' + - '@types/react-dom' + + codemirror@6.0.2: + dependencies: + '@codemirror/autocomplete': 6.20.3 + '@codemirror/commands': 6.10.4 + '@codemirror/language': 6.12.4 + '@codemirror/lint': 6.9.7 + '@codemirror/search': 6.7.1 + '@codemirror/state': 6.7.0 + '@codemirror/view': 6.43.4 + collapse-white-space@2.1.0: {} color-convert@2.0.1: @@ -8182,6 +10857,10 @@ snapshots: color-convert: 2.0.1 color-string: 1.9.1 + combined-stream@1.0.8: + dependencies: + delayed-stream: 1.0.0 + comma-separated-tokens@2.0.3: {} commander@11.1.0: {} @@ -8190,6 +10869,10 @@ snapshots: commander@4.1.1: {} + commander@7.2.0: {} + + commander@8.3.0: {} + common-ancestor-path@1.0.1: {} console-browserify@1.2.0: {} @@ -8212,6 +10895,8 @@ snapshots: cookie@1.1.1: {} + core-js@3.49.0: {} + core-util-is@1.0.3: {} cors@2.8.6: @@ -8219,6 +10904,14 @@ snapshots: object-assign: 4.1.1 vary: 1.1.2 + cose-base@1.0.3: + dependencies: + layout-base: 1.0.2 + + cose-base@2.2.0: + dependencies: + layout-base: 2.0.1 + cpu-features@0.0.10: dependencies: buildcheck: 0.0.7 @@ -8249,6 +10942,8 @@ snapshots: create-require@1.1.1: {} + crelt@1.0.7: {} + cross-spawn@7.0.6: dependencies: path-key: 3.1.1 @@ -8282,8 +10977,6 @@ snapshots: domutils: 3.2.2 nth-check: 2.1.1 - css-selector-parser@3.3.0: {} - css-tree@2.2.1: dependencies: mdn-data: 2.0.28 @@ -8304,18 +10997,210 @@ snapshots: csstype@3.2.3: {} + cytoscape-cose-bilkent@4.1.0(cytoscape@3.34.0): + dependencies: + cose-base: 1.0.3 + cytoscape: 3.34.0 + + cytoscape-fcose@2.2.0(cytoscape@3.34.0): + dependencies: + cose-base: 2.2.0 + cytoscape: 3.34.0 + + cytoscape@3.34.0: {} + + d3-array@2.12.1: + dependencies: + internmap: 1.0.1 + + d3-array@3.2.4: + dependencies: + internmap: 2.0.3 + + d3-axis@3.0.0: {} + + d3-brush@3.0.0: + dependencies: + d3-dispatch: 3.0.1 + d3-drag: 3.0.0 + d3-interpolate: 3.0.1 + d3-selection: 3.0.0 + d3-transition: 3.0.1(d3-selection@3.0.0) + + d3-chord@3.0.1: + dependencies: + d3-path: 3.1.0 + + d3-color@3.1.0: {} + + d3-contour@4.0.2: + dependencies: + d3-array: 3.2.4 + + d3-delaunay@6.0.4: + dependencies: + delaunator: 5.1.0 + + d3-dispatch@3.0.1: {} + + d3-drag@3.0.0: + dependencies: + d3-dispatch: 3.0.1 + d3-selection: 3.0.0 + + d3-dsv@3.0.1: + dependencies: + commander: 7.2.0 + iconv-lite: 0.6.3 + rw: 1.3.3 + + d3-ease@3.0.1: {} + + d3-fetch@3.0.1: + dependencies: + d3-dsv: 3.0.1 + + d3-force@3.0.0: + dependencies: + d3-dispatch: 3.0.1 + d3-quadtree: 3.0.1 + d3-timer: 3.0.1 + + d3-format@3.1.2: {} + + d3-geo@3.1.1: + dependencies: + d3-array: 3.2.4 + + d3-hierarchy@3.1.2: {} + + d3-interpolate@3.0.1: + dependencies: + d3-color: 3.1.0 + + d3-path@1.0.9: {} + + d3-path@3.1.0: {} + + d3-polygon@3.0.1: {} + + d3-quadtree@3.0.1: {} + + d3-random@3.0.1: {} + + d3-sankey@0.12.3: + dependencies: + d3-array: 2.12.1 + d3-shape: 1.3.7 + + d3-scale-chromatic@3.1.0: + dependencies: + d3-color: 3.1.0 + d3-interpolate: 3.0.1 + + d3-scale@4.0.2: + dependencies: + d3-array: 3.2.4 + d3-format: 3.1.2 + d3-interpolate: 3.0.1 + d3-time: 3.1.0 + d3-time-format: 4.1.0 + + d3-selection@3.0.0: {} + + d3-shape@1.3.7: + dependencies: + d3-path: 1.0.9 + + d3-shape@3.2.0: + dependencies: + d3-path: 3.1.0 + + d3-time-format@4.1.0: + dependencies: + d3-time: 3.1.0 + + d3-time@3.1.0: + dependencies: + d3-array: 3.2.4 + + d3-timer@3.0.1: {} + + d3-transition@3.0.1(d3-selection@3.0.0): + dependencies: + d3-color: 3.1.0 + d3-dispatch: 3.0.1 + d3-ease: 3.0.1 + d3-interpolate: 3.0.1 + d3-selection: 3.0.0 + d3-timer: 3.0.1 + + d3-zoom@3.0.0: + dependencies: + d3-dispatch: 3.0.1 + d3-drag: 3.0.0 + d3-interpolate: 3.0.1 + d3-selection: 3.0.0 + d3-transition: 3.0.1(d3-selection@3.0.0) + + d3@7.9.0: + dependencies: + d3-array: 3.2.4 + d3-axis: 3.0.0 + d3-brush: 3.0.0 + d3-chord: 3.0.1 + d3-color: 3.1.0 + d3-contour: 4.0.2 + d3-delaunay: 6.0.4 + d3-dispatch: 3.0.1 + d3-drag: 3.0.0 + d3-dsv: 3.0.1 + d3-ease: 3.0.1 + d3-fetch: 3.0.1 + d3-force: 3.0.0 + d3-format: 3.1.2 + d3-geo: 3.1.1 + d3-hierarchy: 3.1.2 + d3-interpolate: 3.0.1 + d3-path: 3.1.0 + d3-polygon: 3.0.1 + d3-quadtree: 3.0.1 + d3-random: 3.0.1 + d3-scale: 4.0.2 + d3-scale-chromatic: 3.1.0 + d3-selection: 3.0.0 + d3-shape: 3.2.0 + d3-time: 3.1.0 + d3-time-format: 4.1.0 + d3-timer: 3.0.1 + d3-transition: 3.0.1(d3-selection@3.0.0) + d3-zoom: 3.0.0 + + dagre-d3-es@7.0.14: + dependencies: + d3: 7.9.0 + lodash-es: 4.18.1 + data-uri-to-buffer@4.0.1: {} data-uri-to-buffer@6.0.2: {} + date-fns@4.4.0: {} + + dayjs@1.11.21: {} + debug@4.4.3: dependencies: ms: 2.1.3 + decimal.js-light@2.5.1: {} + decode-named-character-reference@1.3.0: dependencies: character-entities: 2.0.2 + dedent@1.7.2: {} + deep-eql@5.0.2: {} define-data-property@1.1.4: @@ -8338,6 +11223,12 @@ snapshots: escodegen: 2.1.0 esprima: 4.0.1 + delaunator@5.1.0: + dependencies: + robust-predicates: 3.0.3 + + delayed-stream@1.0.0: {} + depd@2.0.0: {} dequal@2.0.3: {} @@ -8351,6 +11242,8 @@ snapshots: detect-libc@2.1.2: {} + detect-node-es@1.1.0: {} + deterministic-object-hash@2.0.2: dependencies: base-64: 1.0.0 @@ -8371,8 +11264,6 @@ snapshots: miller-rabin: 4.0.1 randombytes: 2.1.0 - direction@2.0.1: {} - dlv@1.1.3: {} docker-modem@5.0.7: @@ -8398,6 +11289,11 @@ snapshots: - supports-color optional: true + dom-helpers@5.2.1: + dependencies: + '@babel/runtime': 7.29.7 + csstype: 3.2.3 + dom-serializer@2.0.0: dependencies: domelementtype: 2.3.0 @@ -8412,6 +11308,10 @@ snapshots: dependencies: domelementtype: 2.3.0 + dompurify@3.4.11: + optionalDependencies: + '@types/trusted-types': 2.0.7 + domutils@3.2.2: dependencies: dom-serializer: 2.0.0 @@ -8472,6 +11372,15 @@ snapshots: dependencies: es-errors: 1.3.0 + es-set-tostringtag@2.1.0: + dependencies: + es-errors: 1.3.0 + get-intrinsic: 1.3.0 + has-tostringtag: 1.0.2 + hasown: 2.0.4 + + es-toolkit@1.49.0: {} + esast-util-from-estree@2.0.0: dependencies: '@types/estree-jsx': 1.0.5 @@ -8612,6 +11521,11 @@ snapshots: astring: 1.9.0 source-map: 0.7.6 + estree-util-visit@1.2.1: + dependencies: + '@types/estree-jsx': 1.0.5 + '@types/unist': 2.0.11 + estree-util-visit@2.0.0: dependencies: '@types/estree-jsx': 1.0.5 @@ -8627,6 +11541,8 @@ snapshots: etag@1.8.1: {} + eventemitter3@4.0.7: {} + eventemitter3@5.0.4: {} events@3.3.0: {} @@ -8694,13 +11610,6 @@ snapshots: transitivePeerDependencies: - supports-color - expressive-code@0.41.7: - dependencies: - '@expressive-code/core': 0.41.7 - '@expressive-code/plugin-frames': 0.41.7 - '@expressive-code/plugin-shiki': 0.41.7 - '@expressive-code/plugin-text-markers': 0.41.7 - extend@3.0.2: {} extract-zip@2.0.1: @@ -8715,6 +11624,8 @@ snapshots: fast-deep-equal@3.1.3: {} + fast-equals@5.4.0: {} + fast-glob@3.3.3: dependencies: '@nodelib/fs.stat': 2.0.5 @@ -8742,6 +11653,8 @@ snapshots: node-domexception: 1.0.0 web-streams-polyfill: 3.3.3 + fflate@0.4.8: {} + file-type@21.3.4: dependencies: '@tokenizer/inflate': 0.4.1 @@ -8773,6 +11686,8 @@ snapshots: flattie@1.1.1: {} + follow-redirects@1.16.0: {} + fontace@0.4.1: dependencies: fontkitten: 1.0.3 @@ -8790,6 +11705,14 @@ snapshots: cross-spawn: 7.0.6 signal-exit: 4.1.0 + form-data@4.0.6: + dependencies: + asynckit: 0.4.0 + combined-stream: 1.0.8 + es-set-tostringtag: 2.1.0 + hasown: 2.0.4 + mime-types: 2.1.35 + formdata-polyfill@4.0.10: dependencies: fetch-blob: 3.2.0 @@ -8798,6 +11721,15 @@ snapshots: fraction.js@5.3.4: {} + framer-motion@11.18.2(react-dom@19.2.7(react@19.2.7))(react@19.2.7): + dependencies: + motion-dom: 11.18.1 + motion-utils: 11.18.1 + tslib: 2.8.1 + optionalDependencies: + react: 19.2.7 + react-dom: 19.2.7(react@19.2.7) + framer-motion@12.40.0(react-dom@19.2.7(react@19.2.7))(react@19.2.7): dependencies: motion-dom: 12.40.0 @@ -8820,6 +11752,8 @@ snapshots: function-bind@1.1.2: {} + fuse.js@7.4.2: {} + gaxios@7.1.5: dependencies: extend: 3.0.2 @@ -8857,6 +11791,8 @@ snapshots: hasown: 2.0.2 math-intrinsics: 1.1.0 + get-nonce@1.0.1: {} + get-port@7.2.0: optional: true @@ -8937,6 +11873,8 @@ snapshots: ufo: 1.6.4 uncrypto: 0.1.3 + hachure-fill@0.5.2: {} + has-flag@4.0.0: {} has-property-descriptors@1.0.2: @@ -8970,20 +11908,22 @@ snapshots: dependencies: function-bind: 1.1.2 - hast-util-embedded@3.0.0: + hasown@2.0.4: + dependencies: + function-bind: 1.1.2 + + hast-util-from-dom@5.0.1: dependencies: '@types/hast': 3.0.4 - hast-util-is-element: 3.0.0 + hastscript: 9.0.1 + web-namespaces: 2.0.1 - hast-util-format@1.1.0: + hast-util-from-html-isomorphic@2.0.0: dependencies: '@types/hast': 3.0.4 - hast-util-embedded: 3.0.0 - hast-util-minify-whitespace: 1.0.1 - hast-util-phrasing: 3.0.1 - hast-util-whitespace: 3.0.0 - html-whitespace-sensitive-tag-names: 3.0.1 - unist-util-visit-parents: 6.0.2 + hast-util-from-dom: 5.0.1 + hast-util-from-html: 2.0.3 + unist-util-remove-position: 5.0.0 hast-util-from-html@2.0.3: dependencies: @@ -9005,70 +11945,28 @@ snapshots: vfile-location: 5.0.3 web-namespaces: 2.0.1 - hast-util-has-property@3.0.0: - dependencies: - '@types/hast': 3.0.4 - - hast-util-is-body-ok-link@3.0.1: - dependencies: - '@types/hast': 3.0.4 - hast-util-is-element@3.0.0: dependencies: '@types/hast': 3.0.4 - hast-util-minify-whitespace@1.0.1: - dependencies: - '@types/hast': 3.0.4 - hast-util-embedded: 3.0.0 - hast-util-is-element: 3.0.0 - hast-util-whitespace: 3.0.0 - unist-util-is: 6.0.1 - hast-util-parse-selector@4.0.0: dependencies: '@types/hast': 3.0.4 - hast-util-phrasing@3.0.1: - dependencies: - '@types/hast': 3.0.4 - hast-util-embedded: 3.0.0 - hast-util-has-property: 3.0.0 - hast-util-is-body-ok-link: 3.0.1 - hast-util-is-element: 3.0.0 - hast-util-raw@9.1.0: dependencies: '@types/hast': 3.0.4 '@types/unist': 3.0.3 '@ungap/structured-clone': 1.3.1 hast-util-from-parse5: 8.0.3 - hast-util-to-parse5: 8.0.1 - html-void-elements: 3.0.0 - mdast-util-to-hast: 13.2.1 - parse5: 7.3.0 - unist-util-position: 5.0.0 - unist-util-visit: 5.1.0 - vfile: 6.0.3 - web-namespaces: 2.0.1 - zwitch: 2.0.4 - - hast-util-select@6.0.4: - dependencies: - '@types/hast': 3.0.4 - '@types/unist': 3.0.3 - bcp-47-match: 2.0.3 - comma-separated-tokens: 2.0.3 - css-selector-parser: 3.3.0 - devlop: 1.1.0 - direction: 2.0.1 - hast-util-has-property: 3.0.0 - hast-util-to-string: 3.0.1 - hast-util-whitespace: 3.0.0 - nth-check: 2.1.1 - property-information: 7.2.0 - space-separated-tokens: 2.0.2 + hast-util-to-parse5: 8.0.1 + html-void-elements: 3.0.0 + mdast-util-to-hast: 13.2.1 + parse5: 7.3.0 + unist-util-position: 5.0.0 unist-util-visit: 5.1.0 + vfile: 6.0.3 + web-namespaces: 2.0.1 zwitch: 2.0.4 hast-util-to-estree@3.1.3: @@ -9136,10 +12034,6 @@ snapshots: web-namespaces: 2.0.1 zwitch: 2.0.4 - hast-util-to-string@3.0.1: - dependencies: - '@types/hast': 3.0.4 - hast-util-to-text@4.0.2: dependencies: '@types/hast': 3.0.4 @@ -9167,6 +12061,10 @@ snapshots: minimalistic-assert: 1.0.1 minimalistic-crypto-utils: 1.0.1 + hoist-non-react-statics@3.3.2: + dependencies: + react-is: 16.13.1 + hono@4.12.27: {} hosted-git-info@9.0.3: @@ -9175,9 +12073,9 @@ snapshots: html-escaper@3.0.3: {} - html-void-elements@3.0.0: {} + html-url-attributes@3.0.1: {} - html-whitespace-sensitive-tag-names@3.0.1: {} + html-void-elements@3.0.0: {} http-cache-semantics@4.2.0: {} @@ -9198,6 +12096,13 @@ snapshots: https-browserify@1.0.0: {} + https-proxy-agent@5.0.1: + dependencies: + agent-base: 6.0.2 + debug: 4.4.3 + transitivePeerDependencies: + - supports-color + https-proxy-agent@7.0.6: dependencies: agent-base: 7.1.4 @@ -9207,9 +12112,9 @@ snapshots: human-signals@5.0.0: {} - i18next@23.16.8: + iconv-lite@0.6.3: dependencies: - '@babel/runtime': 7.29.7 + safer-buffer: 2.1.2 iconv-lite@0.7.2: dependencies: @@ -9225,6 +12130,15 @@ snapshots: inline-style-parser@0.2.7: {} + input-otp@1.4.2(react-dom@19.2.7(react@19.2.7))(react@19.2.7): + dependencies: + react: 19.2.7 + react-dom: 19.2.7(react@19.2.7) + + internmap@1.0.1: {} + + internmap@2.0.3: {} + ip-address@10.2.0: {} ipaddr.js@1.9.1: {} @@ -9327,6 +12241,17 @@ snapshots: jose@6.2.3: {} + jotai-effect@2.3.1(jotai@2.20.1(@babel/core@7.29.7)(@babel/template@7.29.7)(@types/react@19.2.17)(react@19.2.7)): + dependencies: + jotai: 2.20.1(@babel/core@7.29.7)(@babel/template@7.29.7)(@types/react@19.2.17)(react@19.2.7) + + jotai@2.20.1(@babel/core@7.29.7)(@babel/template@7.29.7)(@types/react@19.2.17)(react@19.2.7): + optionalDependencies: + '@babel/core': 7.29.7 + '@babel/template': 7.29.7 + '@types/react': 19.2.17 + react: 19.2.7 + js-tokens@4.0.0: {} js-yaml@4.2.0: @@ -9361,13 +12286,21 @@ snapshots: jwa: 2.0.1 safe-buffer: 5.2.1 - kleur@3.0.3: {} + katex@0.16.47: + dependencies: + commander: 8.3.0 + + khroma@2.1.0: {} - klona@2.0.6: {} + kleur@3.0.3: {} koffi@2.16.2: optional: true + layout-base@1.0.2: {} + + layout-base@2.0.1: {} + lilconfig@3.1.3: {} lines-and-columns@1.2.4: {} @@ -9380,13 +12313,25 @@ snapshots: dependencies: p-locate: 5.0.0 + lodash-es@4.18.1: {} + lodash.camelcase@4.3.0: optional: true + lodash.debounce@4.0.8: {} + + lodash@4.18.1: {} + + loglevel@1.9.2: {} + long@5.3.2: {} longest-streak@3.1.0: {} + loose-envify@1.4.0: + dependencies: + js-tokens: 4.0.0 + loupe@3.2.1: {} lru-cache@10.4.3: {} @@ -9399,6 +12344,10 @@ snapshots: lru-cache@7.18.3: {} + lucide-react@0.439.0(react@19.2.7): + dependencies: + react: 19.2.7 + lucide-react@0.469.0(react@19.2.7): dependencies: react: 19.2.7 @@ -9430,6 +12379,8 @@ snapshots: marked@15.0.12: {} + marked@16.4.2: {} + math-intrinsics@1.1.0: {} md5.js@1.3.5: @@ -9444,20 +12395,6 @@ snapshots: '@types/unist': 3.0.3 unist-util-visit: 5.1.0 - mdast-util-directive@3.1.0: - dependencies: - '@types/mdast': 4.0.4 - '@types/unist': 3.0.3 - ccount: 2.0.1 - devlop: 1.1.0 - mdast-util-from-markdown: 2.0.3 - mdast-util-to-markdown: 2.1.2 - parse-entities: 4.0.2 - stringify-entities: 4.0.4 - unist-util-visit-parents: 6.0.2 - transitivePeerDependencies: - - supports-color - mdast-util-find-and-replace@3.0.2: dependencies: '@types/mdast': 4.0.4 @@ -9627,6 +12564,12 @@ snapshots: mdurl@2.0.0: {} + mdx-annotations@0.1.4: + dependencies: + acorn: 8.17.0 + estree-util-visit: 1.2.1 + unist-util-visit: 4.1.2 + media-typer@1.1.0: {} merge-descriptors@2.0.0: {} @@ -9635,6 +12578,38 @@ snapshots: merge2@1.4.1: {} + mermaid-isomorphic@3.1.0(playwright@1.59.1): + dependencies: + '@fortawesome/fontawesome-free': 6.7.2 + katex: 0.16.47 + mermaid: 11.16.0 + optionalDependencies: + playwright: 1.59.1 + + mermaid@11.16.0: + dependencies: + '@braintree/sanitize-url': 7.1.2 + '@iconify/utils': 3.1.3 + '@mermaid-js/parser': 1.2.0 + '@types/d3': 7.4.3 + '@upsetjs/venn.js': 2.0.0 + cytoscape: 3.34.0 + cytoscape-cose-bilkent: 4.1.0(cytoscape@3.34.0) + cytoscape-fcose: 2.2.0(cytoscape@3.34.0) + d3: 7.9.0 + d3-sankey: 0.12.3 + dagre-d3-es: 7.0.14 + dayjs: 1.11.21 + dompurify: 3.4.11 + es-toolkit: 1.49.0 + katex: 0.16.47 + khroma: 2.1.0 + marked: 16.4.2 + roughjs: 4.6.6 + stylis: 4.4.0 + ts-dedent: 2.3.0 + uuid: 14.0.1 + micromark-core-commonmark@2.0.3: dependencies: decode-named-character-reference: 1.3.0 @@ -9654,16 +12629,6 @@ snapshots: micromark-util-symbol: 2.0.1 micromark-util-types: 2.0.2 - micromark-extension-directive@3.0.2: - dependencies: - devlop: 1.1.0 - micromark-factory-space: 2.0.1 - micromark-factory-whitespace: 2.0.1 - micromark-util-character: 2.1.1 - micromark-util-symbol: 2.0.1 - micromark-util-types: 2.0.2 - parse-entities: 4.0.2 - micromark-extension-gfm-autolink-literal@2.1.0: dependencies: micromark-util-character: 2.1.1 @@ -9919,14 +12884,22 @@ snapshots: bn.js: 4.12.3 brorand: 1.1.0 + mime-db@1.52.0: {} + mime-db@1.54.0: {} + mime-types@2.1.35: + dependencies: + mime-db: 1.52.0 + mime-types@3.0.2: dependencies: mime-db: 1.54.0 mimic-fn@4.0.0: {} + mini-svg-data-uri@1.4.4: {} + minimalistic-assert@1.0.1: {} minimalistic-crypto-utils@1.0.1: {} @@ -9944,10 +12917,16 @@ snapshots: mkdirp-classic@0.5.3: optional: true + motion-dom@11.18.1: + dependencies: + motion-utils: 11.18.1 + motion-dom@12.40.0: dependencies: motion-utils: 12.39.0 + motion-utils@11.18.1: {} + motion-utils@12.39.0: {} mrmime@2.0.1: {} @@ -10136,16 +13115,6 @@ snapshots: package-manager-detector@1.6.0: {} - pagefind@1.5.2: - optionalDependencies: - '@pagefind/darwin-arm64': 1.5.2 - '@pagefind/darwin-x64': 1.5.2 - '@pagefind/freebsd-x64': 1.5.2 - '@pagefind/linux-arm64': 1.5.2 - '@pagefind/linux-x64': 1.5.2 - '@pagefind/windows-arm64': 1.5.2 - '@pagefind/windows-x64': 1.5.2 - pako@1.0.11: {} parse-asn1@5.1.9: @@ -10193,6 +13162,8 @@ snapshots: path-browserify@1.0.1: {} + path-data-parser@0.1.0: {} + path-exists@4.0.0: {} path-key@3.1.1: {} @@ -10265,6 +13236,13 @@ snapshots: pngjs@7.0.0: {} + points-on-curve@0.2.0: {} + + points-on-path@0.2.1: + dependencies: + path-data-parser: 0.1.0 + points-on-curve: 0.2.0 + possible-typed-array-names@1.1.0: {} postcss-import@15.1.0(postcss@8.5.8): @@ -10300,6 +13278,11 @@ snapshots: postcss: 8.5.8 postcss-selector-parser: 6.1.4 + postcss-selector-parser@6.0.10: + dependencies: + cssesc: 3.0.0 + util-deprecate: 1.0.2 + postcss-selector-parser@6.1.4: dependencies: cssesc: 3.0.0 @@ -10313,6 +13296,19 @@ snapshots: picocolors: 1.1.1 source-map-js: 1.2.1 + posthog-js@1.395.0: + dependencies: + '@posthog/core': 1.38.0 + '@posthog/types': 1.391.1 + core-js: 3.49.0 + dompurify: 3.4.11 + fflate: 0.4.8 + preact: 10.29.3 + query-selector-shadow-dom: 1.0.1 + web-vitals: 5.3.0 + + preact@10.29.3: {} + prismjs@1.30.0: {} process-nextick-args@2.0.1: {} @@ -10324,6 +13320,12 @@ snapshots: kleur: 3.0.3 sisteransi: 1.0.5 + prop-types@15.8.1: + dependencies: + loose-envify: 1.4.0 + object-assign: 4.1.1 + react-is: 16.13.1 + proper-lockfile@4.1.2: dependencies: graceful-fs: 4.2.11 @@ -10367,6 +13369,8 @@ snapshots: proxy-from-env@1.1.0: {} + proxy-from-env@2.1.0: {} + public-encrypt@4.0.3: dependencies: bn.js: 4.12.3 @@ -10394,6 +13398,8 @@ snapshots: es-define-property: 1.0.1 side-channel: 1.1.1 + query-selector-shadow-dom@1.0.1: {} + querystring-es3@0.2.1: {} queue-microtask@1.2.3: {} @@ -10418,13 +13424,117 @@ snapshots: iconv-lite: 0.7.2 unpipe: 1.0.0 + react-aria@3.50.0(react-dom@19.2.7(react@19.2.7))(react@19.2.7): + dependencies: + '@internationalized/date': 3.12.2 + '@internationalized/number': 3.6.7 + '@internationalized/string': 3.2.9 + '@react-types/shared': 3.36.0(react@19.2.7) + '@swc/helpers': 0.5.23 + aria-hidden: 1.2.6 + clsx: 2.1.1 + react: 19.2.7 + react-dom: 19.2.7(react@19.2.7) + react-stately: 3.48.0(react@19.2.7) + use-sync-external-store: 1.6.0(react@19.2.7) + + react-day-picker@8.10.1(date-fns@4.4.0)(react@19.2.7): + dependencies: + date-fns: 4.4.0 + react: 19.2.7 + react-dom@19.2.7(react@19.2.7): dependencies: react: 19.2.7 scheduler: 0.27.0 + react-hook-form@7.80.0(react@19.2.7): + dependencies: + react: 19.2.7 + + react-is@16.13.1: {} + + react-is@18.3.1: {} + + react-markdown@10.1.0(@types/react@19.2.17)(react@19.2.7): + dependencies: + '@types/hast': 3.0.4 + '@types/mdast': 4.0.4 + '@types/react': 19.2.17 + devlop: 1.1.0 + hast-util-to-jsx-runtime: 2.3.6 + html-url-attributes: 3.0.1 + mdast-util-to-hast: 13.2.1 + react: 19.2.7 + remark-parse: 11.0.0 + remark-rehype: 11.1.2 + unified: 11.0.5 + unist-util-visit: 5.1.0 + vfile: 6.0.3 + transitivePeerDependencies: + - supports-color + react-refresh@0.17.0: {} + react-remove-scroll-bar@2.3.8(@types/react@19.2.17)(react@19.2.7): + dependencies: + react: 19.2.7 + react-style-singleton: 2.2.3(@types/react@19.2.17)(react@19.2.7) + tslib: 2.8.1 + optionalDependencies: + '@types/react': 19.2.17 + + react-remove-scroll@2.7.2(@types/react@19.2.17)(react@19.2.7): + dependencies: + react: 19.2.7 + react-remove-scroll-bar: 2.3.8(@types/react@19.2.17)(react@19.2.7) + react-style-singleton: 2.2.3(@types/react@19.2.17)(react@19.2.7) + tslib: 2.8.1 + use-callback-ref: 1.3.3(@types/react@19.2.17)(react@19.2.7) + use-sidecar: 1.1.3(@types/react@19.2.17)(react@19.2.7) + optionalDependencies: + '@types/react': 19.2.17 + + react-resizable-panels@2.1.9(react-dom@19.2.7(react@19.2.7))(react@19.2.7): + dependencies: + react: 19.2.7 + react-dom: 19.2.7(react@19.2.7) + + react-smooth@4.0.4(react-dom@19.2.7(react@19.2.7))(react@19.2.7): + dependencies: + fast-equals: 5.4.0 + prop-types: 15.8.1 + react: 19.2.7 + react-dom: 19.2.7(react@19.2.7) + react-transition-group: 4.4.5(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + + react-stately@3.48.0(react@19.2.7): + dependencies: + '@internationalized/date': 3.12.2 + '@internationalized/number': 3.6.7 + '@internationalized/string': 3.2.9 + '@react-types/shared': 3.36.0(react@19.2.7) + '@swc/helpers': 0.5.23 + react: 19.2.7 + use-sync-external-store: 1.6.0(react@19.2.7) + + react-style-singleton@2.2.3(@types/react@19.2.17)(react@19.2.7): + dependencies: + get-nonce: 1.0.1 + react: 19.2.7 + tslib: 2.8.1 + optionalDependencies: + '@types/react': 19.2.17 + + react-transition-group@4.4.5(react-dom@19.2.7(react@19.2.7))(react@19.2.7): + dependencies: + '@babel/runtime': 7.29.7 + dom-helpers: 5.2.1 + loose-envify: 1.4.0 + prop-types: 15.8.1 + react: 19.2.7 + react-dom: 19.2.7(react@19.2.7) + react@19.2.7: {} read-cache@1.0.0: @@ -10453,6 +13563,23 @@ snapshots: readdirp@5.0.0: {} + recharts-scale@0.4.5: + dependencies: + decimal.js-light: 2.5.1 + + recharts@2.15.4(react-dom@19.2.7(react@19.2.7))(react@19.2.7): + dependencies: + clsx: 2.1.1 + eventemitter3: 4.0.7 + lodash: 4.18.1 + react: 19.2.7 + react-dom: 19.2.7(react@19.2.7) + react-is: 18.3.1 + react-smooth: 4.0.4(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + recharts-scale: 0.4.5 + tiny-invariant: 1.3.3 + victory-vendor: 36.9.2 + recma-build-jsx@1.0.0: dependencies: '@types/estree': 1.0.8 @@ -10492,14 +13619,19 @@ snapshots: dependencies: regex-utilities: 2.3.0 - rehype-expressive-code@0.41.7: - dependencies: - expressive-code: 0.41.7 - - rehype-format@5.0.1: + rehype-mermaid@3.0.0(playwright@1.59.1): dependencies: '@types/hast': 3.0.4 - hast-util-format: 1.1.0 + hast-util-from-html-isomorphic: 2.0.0 + hast-util-to-text: 4.0.2 + mermaid-isomorphic: 3.1.0(playwright@1.59.1) + mini-svg-data-uri: 1.4.4 + space-separated-tokens: 2.0.2 + unified: 11.0.5 + unist-util-visit-parents: 6.0.2 + vfile: 6.0.3 + optionalDependencies: + playwright: 1.59.1 rehype-parse@9.0.1: dependencies: @@ -10534,15 +13666,6 @@ snapshots: rehype-stringify: 10.0.1 unified: 11.0.5 - remark-directive@3.0.1: - dependencies: - '@types/mdast': 4.0.4 - mdast-util-directive: 3.1.0 - micromark-extension-directive: 3.0.2 - unified: 11.0.5 - transitivePeerDependencies: - - supports-color - remark-gfm@4.0.1: dependencies: '@types/mdast': 4.0.4 @@ -10639,6 +13762,8 @@ snapshots: hash-base: 3.1.2 inherits: 2.0.4 + robust-predicates@3.0.3: {} + rollup@4.60.1: dependencies: '@types/estree': 1.0.8 @@ -10670,6 +13795,13 @@ snapshots: '@rollup/rollup-win32-x64-msvc': 4.60.1 fsevents: 2.3.3 + roughjs@4.6.6: + dependencies: + hachure-fill: 0.5.2 + path-data-parser: 0.1.0 + points-on-curve: 0.2.0 + points-on-path: 0.2.1 + router@2.2.0: dependencies: debug: 4.4.3 @@ -10684,6 +13816,8 @@ snapshots: dependencies: queue-microtask: 1.2.3 + rw@1.3.3: {} + safe-buffer@5.1.2: {} safe-buffer@5.2.1: {} @@ -10911,6 +14045,11 @@ snapshots: ip-address: 10.2.0 smart-buffer: 4.2.0 + sonner@1.7.4(react-dom@19.2.7(react@19.2.7))(react@19.2.7): + dependencies: + react: 19.2.7 + react-dom: 19.2.7(react@19.2.7) + source-map-js@1.2.1: {} source-map@0.6.1: @@ -10997,6 +14136,8 @@ snapshots: dependencies: '@tokenizer/token': 0.3.0 + style-mod@4.1.3: {} + style-to-js@1.1.21: dependencies: style-to-object: 1.0.14 @@ -11005,6 +14146,8 @@ snapshots: dependencies: inline-style-parser: 0.2.7 + stylis@4.4.0: {} + sucrase@3.35.1: dependencies: '@jridgewell/gen-mapping': 0.3.13 @@ -11031,6 +14174,14 @@ snapshots: picocolors: 1.1.1 sax: 1.6.0 + tabbable@6.5.0: {} + + tailwind-merge@2.6.1: {} + + tailwindcss-animate@1.0.7(tailwindcss@3.4.19(tsx@4.21.0)(yaml@2.9.0)): + dependencies: + tailwindcss: 3.4.19(tsx@4.21.0)(yaml@2.9.0) + tailwindcss@3.4.19(tsx@4.21.0)(yaml@2.9.0): dependencies: '@alloc/quick-lru': 5.2.0 @@ -11090,6 +14241,8 @@ snapshots: tiny-inflate@1.0.3: {} + tiny-invariant@1.3.3: {} + tinybench@2.9.0: {} tinyexec@0.3.2: {} @@ -11107,6 +14260,8 @@ snapshots: tinyspy@3.0.2: {} + tm-themes@1.12.2: {} + to-buffer@1.2.2: dependencies: isarray: 2.0.5 @@ -11131,6 +14286,8 @@ snapshots: ts-algebra@2.0.0: {} + ts-dedent@2.3.0: {} + ts-interface-checker@0.1.13: {} tsconfck@3.1.6(typescript@5.9.3): @@ -11189,6 +14346,16 @@ snapshots: typescript@5.9.3: {} + typesense@2.1.0(@babel/runtime@7.29.7): + dependencies: + '@babel/runtime': 7.29.7 + axios: 1.18.1 + loglevel: 1.9.2 + tslib: 2.8.1 + transitivePeerDependencies: + - debug + - supports-color + uc.micro@2.1.0: {} ufo@1.6.4: {} @@ -11221,11 +14388,21 @@ snapshots: ofetch: 1.5.1 ohash: 2.0.11 + unist-util-filter@5.0.1: + dependencies: + '@types/unist': 3.0.3 + unist-util-is: 6.0.1 + unist-util-visit-parents: 6.0.2 + unist-util-find-after@5.0.0: dependencies: '@types/unist': 3.0.3 unist-util-is: 6.0.1 + unist-util-is@5.2.1: + dependencies: + '@types/unist': 2.0.11 + unist-util-is@6.0.1: dependencies: '@types/unist': 3.0.3 @@ -11256,11 +14433,22 @@ snapshots: dependencies: '@types/unist': 3.0.3 + unist-util-visit-parents@5.1.3: + dependencies: + '@types/unist': 2.0.11 + unist-util-is: 5.2.1 + unist-util-visit-parents@6.0.2: dependencies: '@types/unist': 3.0.3 unist-util-is: 6.0.1 + unist-util-visit@4.1.2: + dependencies: + '@types/unist': 2.0.11 + unist-util-is: 5.2.1 + unist-util-visit-parents: 5.1.3 + unist-util-visit@5.1.0: dependencies: '@types/unist': 3.0.3 @@ -11291,6 +14479,30 @@ snapshots: punycode: 1.4.1 qs: 6.15.0 + use-callback-ref@1.3.3(@types/react@19.2.17)(react@19.2.7): + dependencies: + react: 19.2.7 + tslib: 2.8.1 + optionalDependencies: + '@types/react': 19.2.17 + + use-sidecar@1.1.3(@types/react@19.2.17)(react@19.2.7): + dependencies: + detect-node-es: 1.1.0 + react: 19.2.7 + tslib: 2.8.1 + optionalDependencies: + '@types/react': 19.2.17 + + use-sync-external-store@1.6.0(react@19.2.7): + dependencies: + react: 19.2.7 + + usehooks-ts@3.1.1(react@19.2.7): + dependencies: + lodash.debounce: 4.0.8 + react: 19.2.7 + util-deprecate@1.0.2: {} util@0.12.5: @@ -11304,6 +14516,8 @@ snapshots: uuid@10.0.0: optional: true + uuid@14.0.1: {} + vary@1.1.2: {} vfile-location@5.0.3: @@ -11321,6 +14535,23 @@ snapshots: '@types/unist': 3.0.3 vfile-message: 4.0.3 + victory-vendor@36.9.2: + dependencies: + '@types/d3-array': 3.2.2 + '@types/d3-ease': 3.0.2 + '@types/d3-interpolate': 3.0.4 + '@types/d3-scale': 4.0.9 + '@types/d3-shape': 3.1.8 + '@types/d3-time': 3.0.4 + '@types/d3-timer': 3.0.2 + d3-array: 3.2.4 + d3-ease: 3.0.1 + d3-interpolate: 3.0.1 + d3-scale: 4.0.2 + d3-shape: 3.2.0 + d3-time: 3.1.0 + d3-timer: 3.0.1 + vite-node@2.1.9(@types/node@22.19.15): dependencies: cac: 6.7.14 @@ -11404,10 +14635,14 @@ snapshots: vm-browserify@1.1.2: {} + w3c-keyname@2.2.8: {} + web-namespaces@2.0.1: {} web-streams-polyfill@3.3.3: {} + web-vitals@5.3.0: {} + which-pm-runs@1.1.0: {} which-typed-array@1.1.20: @@ -11522,4 +14757,10 @@ snapshots: zod@4.3.6: {} + zustand@5.0.14(@types/react@19.2.17)(react@19.2.7)(use-sync-external-store@1.6.0(react@19.2.7)): + optionalDependencies: + '@types/react': 19.2.17 + react: 19.2.7 + use-sync-external-store: 1.6.0(react@19.2.7) + zwitch@2.0.4: {} diff --git a/website/.astro/collections/docs.schema.json b/website/.astro/collections/docs.schema.json index 9500aa03f..fd3ef3bfe 100644 --- a/website/.astro/collections/docs.schema.json +++ b/website/.astro/collections/docs.schema.json @@ -10,628 +10,6 @@ "description": { "type": "string" }, - "editUrl": { - "anyOf": [ - { - "type": "string", - "format": "uri" - }, - { - "type": "boolean" - } - ], - "default": true - }, - "head": { - "type": "array", - "items": { - "type": "object", - "properties": { - "tag": { - "type": "string", - "enum": [ - "title", - "base", - "link", - "style", - "meta", - "script", - "noscript", - "template" - ] - }, - "attrs": { - "type": "object", - "additionalProperties": { - "anyOf": [ - { - "type": "string" - }, - { - "type": "boolean" - }, - { - "not": {} - } - ] - } - }, - "content": { - "type": "string" - } - }, - "required": [ - "tag" - ], - "additionalProperties": false - }, - "default": [] - }, - "tableOfContents": { - "anyOf": [ - { - "type": "object", - "properties": { - "minHeadingLevel": { - "type": "integer", - "minimum": 1, - "maximum": 6, - "default": 2 - }, - "maxHeadingLevel": { - "type": "integer", - "minimum": 1, - "maximum": 6, - "default": 3 - } - }, - "additionalProperties": false - }, - { - "type": "boolean" - } - ], - "default": { - "minHeadingLevel": 2, - "maxHeadingLevel": 3 - } - }, - "template": { - "type": "string", - "enum": [ - "doc", - "splash" - ], - "default": "doc" - }, - "hero": { - "type": "object", - "properties": { - "title": { - "type": "string" - }, - "tagline": { - "type": "string" - }, - "image": { - "anyOf": [ - { - "type": "object", - "properties": { - "alt": { - "type": "string", - "default": "" - }, - "file": { - "type": "string" - } - }, - "required": [ - "file" - ], - "additionalProperties": false - }, - { - "type": "object", - "properties": { - "alt": { - "type": "string", - "default": "" - }, - "dark": { - "type": "string" - }, - "light": { - "type": "string" - } - }, - "required": [ - "dark", - "light" - ], - "additionalProperties": false - }, - { - "type": "object", - "properties": { - "html": { - "type": "string" - } - }, - "required": [ - "html" - ], - "additionalProperties": false - } - ] - }, - "actions": { - "type": "array", - "items": { - "type": "object", - "properties": { - "text": { - "type": "string" - }, - "link": { - "type": "string" - }, - "variant": { - "type": "string", - "enum": [ - "primary", - "secondary", - "minimal" - ], - "default": "primary" - }, - "icon": { - "anyOf": [ - { - "type": "string", - "enum": [ - "up-caret", - "down-caret", - "right-caret", - "left-caret", - "up-arrow", - "down-arrow", - "right-arrow", - "left-arrow", - "bars", - "translate", - "pencil", - "pen", - "document", - "add-document", - "setting", - "external", - "download", - "cloud-download", - "moon", - "sun", - "laptop", - "open-book", - "information", - "magnifier", - "forward-slash", - "close", - "error", - "warning", - "approve-check-circle", - "approve-check", - "rocket", - "star", - "puzzle", - "list-format", - "random", - "comment", - "comment-alt", - "heart", - "github", - "gitlab", - "bitbucket", - "codePen", - "farcaster", - "discord", - "gitter", - "twitter", - "x.com", - "mastodon", - "codeberg", - "youtube", - "threads", - "linkedin", - "twitch", - "azureDevOps", - "microsoftTeams", - "instagram", - "stackOverflow", - "telegram", - "rss", - "facebook", - "email", - "phone", - "reddit", - "patreon", - "signal", - "slack", - "matrix", - "hackerOne", - "openCollective", - "blueSky", - "discourse", - "zulip", - "pinterest", - "tiktok", - "astro", - "alpine", - "pnpm", - "biome", - "bun", - "mdx", - "apple", - "linux", - "homebrew", - "nix", - "starlight", - "pkl", - "node", - "cloudflare", - "vercel", - "netlify", - "deno", - "jsr", - "nostr", - "backstage", - "confluence", - "jira", - "storybook", - "vscode", - "jetbrains", - "zed", - "vim", - "figma", - "sketch", - "npm", - "sourcehut", - "substack", - "seti:folder", - "seti:bsl", - "seti:mdo", - "seti:salesforce", - "seti:asm", - "seti:bicep", - "seti:bazel", - "seti:c", - "seti:c-sharp", - "seti:html", - "seti:cpp", - "seti:clojure", - "seti:coldfusion", - "seti:config", - "seti:crystal", - "seti:crystal_embedded", - "seti:json", - "seti:css", - "seti:csv", - "seti:xls", - "seti:cu", - "seti:cake", - "seti:cake_php", - "seti:d", - "seti:word", - "seti:elixir", - "seti:elixir_script", - "seti:hex", - "seti:elm", - "seti:favicon", - "seti:f-sharp", - "seti:git", - "seti:go", - "seti:godot", - "seti:gradle", - "seti:grails", - "seti:graphql", - "seti:hacklang", - "seti:haml", - "seti:mustache", - "seti:haskell", - "seti:haxe", - "seti:jade", - "seti:java", - "seti:javascript", - "seti:jinja", - "seti:julia", - "seti:karma", - "seti:kotlin", - "seti:dart", - "seti:liquid", - "seti:livescript", - "seti:lua", - "seti:markdown", - "seti:argdown", - "seti:info", - "seti:clock", - "seti:maven", - "seti:nim", - "seti:github", - "seti:notebook", - "seti:nunjucks", - "seti:npm", - "seti:ocaml", - "seti:odata", - "seti:perl", - "seti:php", - "seti:pipeline", - "seti:pddl", - "seti:plan", - "seti:happenings", - "seti:powershell", - "seti:prisma", - "seti:pug", - "seti:puppet", - "seti:purescript", - "seti:python", - "seti:react", - "seti:rescript", - "seti:R", - "seti:ruby", - "seti:rust", - "seti:sass", - "seti:spring", - "seti:slim", - "seti:smarty", - "seti:sbt", - "seti:scala", - "seti:ethereum", - "seti:stylus", - "seti:svelte", - "seti:swift", - "seti:db", - "seti:terraform", - "seti:tex", - "seti:default", - "seti:twig", - "seti:typescript", - "seti:tsconfig", - "seti:vala", - "seti:vite", - "seti:vue", - "seti:wasm", - "seti:wat", - "seti:xml", - "seti:yml", - "seti:prolog", - "seti:zig", - "seti:zip", - "seti:wgt", - "seti:illustrator", - "seti:photoshop", - "seti:pdf", - "seti:font", - "seti:image", - "seti:svg", - "seti:sublime", - "seti:code-search", - "seti:shell", - "seti:video", - "seti:audio", - "seti:windows", - "seti:jenkins", - "seti:babel", - "seti:bower", - "seti:docker", - "seti:code-climate", - "seti:eslint", - "seti:firebase", - "seti:firefox", - "seti:gitlab", - "seti:grunt", - "seti:gulp", - "seti:ionic", - "seti:platformio", - "seti:rollup", - "seti:stylelint", - "seti:yarn", - "seti:webpack", - "seti:lock", - "seti:license", - "seti:makefile", - "seti:heroku", - "seti:todo", - "seti:ignored" - ] - }, - { - "type": "string", - "pattern": "^\\ import("astro:content-layer-deferred-module?astro%3Acontent-layer-deferred-module=&fileName=src%2Fcontent%2Fdocs%2Fdocs%2Farchitecture.mdx&astroContentModuleFlag=true")], -["src/content/docs/docs/crash-course.mdx", () => import("astro:content-layer-deferred-module?astro%3Acontent-layer-deferred-module=&fileName=src%2Fcontent%2Fdocs%2Fdocs%2Fcrash-course.mdx&astroContentModuleFlag=true")], ["src/content/docs/docs/benchmarks.mdx", () => import("astro:content-layer-deferred-module?astro%3Acontent-layer-deferred-module=&fileName=src%2Fcontent%2Fdocs%2Fdocs%2Fbenchmarks.mdx&astroContentModuleFlag=true")], +["src/content/docs/docs/crash-course.mdx", () => import("astro:content-layer-deferred-module?astro%3Acontent-layer-deferred-module=&fileName=src%2Fcontent%2Fdocs%2Fdocs%2Fcrash-course.mdx&astroContentModuleFlag=true")], ["src/content/docs/docs/index.mdx", () => import("astro:content-layer-deferred-module?astro%3Acontent-layer-deferred-module=&fileName=src%2Fcontent%2Fdocs%2Fdocs%2Findex.mdx&astroContentModuleFlag=true")], ["src/content/docs/docs/nodejs-compatibility.mdx", () => import("astro:content-layer-deferred-module?astro%3Acontent-layer-deferred-module=&fileName=src%2Fcontent%2Fdocs%2Fdocs%2Fnodejs-compatibility.mdx&astroContentModuleFlag=true")], ["src/content/docs/docs/quickstart.mdx", () => import("astro:content-layer-deferred-module?astro%3Acontent-layer-deferred-module=&fileName=src%2Fcontent%2Fdocs%2Fdocs%2Fquickstart.mdx&astroContentModuleFlag=true")], @@ -10,14 +10,8 @@ export default new Map([ ["src/content/docs/docs/comparison/cloudflare-workers.mdx", () => import("astro:content-layer-deferred-module?astro%3Acontent-layer-deferred-module=&fileName=src%2Fcontent%2Fdocs%2Fdocs%2Fcomparison%2Fcloudflare-workers.mdx&astroContentModuleFlag=true")], ["src/content/docs/docs/comparison/isolated-vm.mdx", () => import("astro:content-layer-deferred-module?astro%3Acontent-layer-deferred-module=&fileName=src%2Fcontent%2Fdocs%2Fdocs%2Fcomparison%2Fisolated-vm.mdx&astroContentModuleFlag=true")], ["src/content/docs/docs/comparison/quickjs.mdx", () => import("astro:content-layer-deferred-module?astro%3Acontent-layer-deferred-module=&fileName=src%2Fcontent%2Fdocs%2Fdocs%2Fcomparison%2Fquickjs.mdx&astroContentModuleFlag=true")], -["src/content/docs/docs/sdks/rust.mdx", () => import("astro:content-layer-deferred-module?astro%3Acontent-layer-deferred-module=&fileName=src%2Fcontent%2Fdocs%2Fdocs%2Fsdks%2Frust.mdx&astroContentModuleFlag=true")], -["src/content/docs/docs/sdks/typescript.mdx", () => import("astro:content-layer-deferred-module?astro%3Acontent-layer-deferred-module=&fileName=src%2Fcontent%2Fdocs%2Fdocs%2Fsdks%2Ftypescript.mdx&astroContentModuleFlag=true")], ["src/content/docs/docs/comparison/sandbox.mdx", () => import("astro:content-layer-deferred-module?astro%3Acontent-layer-deferred-module=&fileName=src%2Fcontent%2Fdocs%2Fdocs%2Fcomparison%2Fsandbox.mdx&astroContentModuleFlag=true")], -["src/content/docs/docs/use-cases/ai-agent-code-exec.mdx", () => import("astro:content-layer-deferred-module?astro%3Acontent-layer-deferred-module=&fileName=src%2Fcontent%2Fdocs%2Fdocs%2Fuse-cases%2Fai-agent-code-exec.mdx&astroContentModuleFlag=true")], -["src/content/docs/docs/use-cases/code-mode.mdx", () => import("astro:content-layer-deferred-module?astro%3Acontent-layer-deferred-module=&fileName=src%2Fcontent%2Fdocs%2Fdocs%2Fuse-cases%2Fcode-mode.mdx&astroContentModuleFlag=true")], -["src/content/docs/docs/use-cases/dev-servers.mdx", () => import("astro:content-layer-deferred-module?astro%3Acontent-layer-deferred-module=&fileName=src%2Fcontent%2Fdocs%2Fdocs%2Fuse-cases%2Fdev-servers.mdx&astroContentModuleFlag=true")], ["src/content/docs/docs/features/bindings.mdx", () => import("astro:content-layer-deferred-module?astro%3Acontent-layer-deferred-module=&fileName=src%2Fcontent%2Fdocs%2Fdocs%2Ffeatures%2Fbindings.mdx&astroContentModuleFlag=true")], -["src/content/docs/docs/use-cases/plugin-systems.mdx", () => import("astro:content-layer-deferred-module?astro%3Acontent-layer-deferred-module=&fileName=src%2Fcontent%2Fdocs%2Fdocs%2Fuse-cases%2Fplugin-systems.mdx&astroContentModuleFlag=true")], ["src/content/docs/docs/features/child-processes.mdx", () => import("astro:content-layer-deferred-module?astro%3Acontent-layer-deferred-module=&fileName=src%2Fcontent%2Fdocs%2Fdocs%2Ffeatures%2Fchild-processes.mdx&astroContentModuleFlag=true")], ["src/content/docs/docs/features/executing-code.mdx", () => import("astro:content-layer-deferred-module?astro%3Acontent-layer-deferred-module=&fileName=src%2Fcontent%2Fdocs%2Fdocs%2Ffeatures%2Fexecuting-code.mdx&astroContentModuleFlag=true")], ["src/content/docs/docs/features/filesystem.mdx", () => import("astro:content-layer-deferred-module?astro%3Acontent-layer-deferred-module=&fileName=src%2Fcontent%2Fdocs%2Fdocs%2Ffeatures%2Ffilesystem.mdx&astroContentModuleFlag=true")], @@ -28,5 +22,11 @@ export default new Map([ ["src/content/docs/docs/features/resident-runner.mdx", () => import("astro:content-layer-deferred-module?astro%3Acontent-layer-deferred-module=&fileName=src%2Fcontent%2Fdocs%2Fdocs%2Ffeatures%2Fresident-runner.mdx&astroContentModuleFlag=true")], ["src/content/docs/docs/features/resource-limits.mdx", () => import("astro:content-layer-deferred-module?astro%3Acontent-layer-deferred-module=&fileName=src%2Fcontent%2Fdocs%2Fdocs%2Ffeatures%2Fresource-limits.mdx&astroContentModuleFlag=true")], ["src/content/docs/docs/features/runtime-platform.mdx", () => import("astro:content-layer-deferred-module?astro%3Acontent-layer-deferred-module=&fileName=src%2Fcontent%2Fdocs%2Fdocs%2Ffeatures%2Fruntime-platform.mdx&astroContentModuleFlag=true")], -["src/content/docs/docs/features/typescript.mdx", () => import("astro:content-layer-deferred-module?astro%3Acontent-layer-deferred-module=&fileName=src%2Fcontent%2Fdocs%2Fdocs%2Ffeatures%2Ftypescript.mdx&astroContentModuleFlag=true")]]); +["src/content/docs/docs/features/typescript.mdx", () => import("astro:content-layer-deferred-module?astro%3Acontent-layer-deferred-module=&fileName=src%2Fcontent%2Fdocs%2Fdocs%2Ffeatures%2Ftypescript.mdx&astroContentModuleFlag=true")], +["src/content/docs/docs/sdks/rust.mdx", () => import("astro:content-layer-deferred-module?astro%3Acontent-layer-deferred-module=&fileName=src%2Fcontent%2Fdocs%2Fdocs%2Fsdks%2Frust.mdx&astroContentModuleFlag=true")], +["src/content/docs/docs/sdks/typescript.mdx", () => import("astro:content-layer-deferred-module?astro%3Acontent-layer-deferred-module=&fileName=src%2Fcontent%2Fdocs%2Fdocs%2Fsdks%2Ftypescript.mdx&astroContentModuleFlag=true")], +["src/content/docs/docs/use-cases/ai-agent-code-exec.mdx", () => import("astro:content-layer-deferred-module?astro%3Acontent-layer-deferred-module=&fileName=src%2Fcontent%2Fdocs%2Fdocs%2Fuse-cases%2Fai-agent-code-exec.mdx&astroContentModuleFlag=true")], +["src/content/docs/docs/use-cases/code-mode.mdx", () => import("astro:content-layer-deferred-module?astro%3Acontent-layer-deferred-module=&fileName=src%2Fcontent%2Fdocs%2Fdocs%2Fuse-cases%2Fcode-mode.mdx&astroContentModuleFlag=true")], +["src/content/docs/docs/use-cases/dev-servers.mdx", () => import("astro:content-layer-deferred-module?astro%3Acontent-layer-deferred-module=&fileName=src%2Fcontent%2Fdocs%2Fdocs%2Fuse-cases%2Fdev-servers.mdx&astroContentModuleFlag=true")], +["src/content/docs/docs/use-cases/plugin-systems.mdx", () => import("astro:content-layer-deferred-module?astro%3Acontent-layer-deferred-module=&fileName=src%2Fcontent%2Fdocs%2Fdocs%2Fuse-cases%2Fplugin-systems.mdx&astroContentModuleFlag=true")]]); \ No newline at end of file diff --git a/website/.astro/data-store.json b/website/.astro/data-store.json index 6310431d4..a3e93df70 100644 --- a/website/.astro/data-store.json +++ b/website/.astro/data-store.json @@ -1 +1 @@ -[["Map",1,2,9,10],"meta::meta",["Map",3,4,5,6,7,8],"astro-version","5.18.2","content-config-digest","3edc204469c72622","astro-config-digest","{\"root\":{},\"srcDir\":{},\"publicDir\":{},\"outDir\":{},\"cacheDir\":{},\"site\":\"https://secureexec.dev\",\"compressHTML\":true,\"base\":\"/\",\"trailingSlash\":\"ignore\",\"output\":\"static\",\"scopedStyleStrategy\":\"where\",\"build\":{\"format\":\"directory\",\"client\":{},\"server\":{},\"assets\":\"_astro\",\"serverEntry\":\"entry.mjs\",\"redirects\":true,\"inlineStylesheets\":\"auto\",\"concurrency\":1},\"server\":{\"open\":false,\"host\":false,\"port\":4322,\"streaming\":true,\"allowedHosts\":[]},\"redirects\":{},\"image\":{\"endpoint\":{\"route\":\"/_image\"},\"service\":{\"entrypoint\":\"astro/assets/services/sharp\",\"config\":{}},\"domains\":[],\"remotePatterns\":[],\"responsiveStyles\":false},\"devToolbar\":{\"enabled\":true},\"markdown\":{\"syntaxHighlight\":false,\"shikiConfig\":{\"langs\":[],\"langAlias\":{},\"theme\":\"github-dark\",\"themes\":{},\"wrap\":false,\"transformers\":[]},\"remarkPlugins\":[null,null,null],\"rehypePlugins\":[null,[null,{\"experimentalHeadingIdCompat\":false}],null,[null,{\"themes\":[\"github-dark-default\"],\"defaultLocale\":\"en\",\"cascadeLayer\":\"starlight.components\",\"styleOverrides\":{\"borderRadius\":\"0.75rem\",\"borderWidth\":\"1px\",\"codePaddingBlock\":\"0.75rem\",\"codePaddingInline\":\"1rem\",\"codeFontFamily\":\"\\\"JetBrains Mono\\\", ui-monospace, SFMono-Regular, Menlo, monospace\",\"codeFontSize\":\"var(--sl-text-code)\",\"codeLineHeight\":\"var(--sl-line-height)\",\"uiFontFamily\":\"var(--__sl-font)\",\"textMarkers\":{\"lineDiffIndicatorMarginLeft\":\"0.25rem\",\"defaultChroma\":\"45\",\"backgroundOpacity\":\"60%\"},\"borderColor\":\"rgba(244, 241, 231, 0.1)\",\"codeBackground\":\"#0a0a0a\",\"frames\":{\"editorTabBarBackground\":\"#111110\",\"editorTabBarBorderBottomColor\":\"rgba(244, 241, 231, 0.1)\",\"editorActiveTabBackground\":\"#0a0a0a\",\"editorActiveTabIndicatorBottomColor\":\"#cb5a33\",\"terminalTitlebarBackground\":\"#111110\",\"terminalBackground\":\"#0a0a0a\",\"frameBoxShadowCssValue\":\"none\"}},\"plugins\":[{\"name\":\"Starlight Plugin\",\"hooks\":{}},{\"name\":\"astro-expressive-code\",\"hooks\":{}}]}]],\"remarkRehype\":{},\"gfm\":true,\"smartypants\":true},\"security\":{\"checkOrigin\":true,\"allowedDomains\":[],\"actionBodySizeLimit\":1048576},\"env\":{\"schema\":{},\"validateSecrets\":false},\"experimental\":{\"clientPrerender\":false,\"contentIntellisense\":false,\"headingIdCompat\":false,\"preserveScriptOrder\":false,\"liveContentCollections\":false,\"csp\":false,\"staticImportMetaEnv\":false,\"chromeDevtoolsWorkspace\":false,\"failOnPrerenderConflict\":false,\"svgo\":false},\"legacy\":{\"collections\":false},\"prefetch\":{\"prefetchAll\":true},\"i18n\":{\"defaultLocale\":\"en\",\"locales\":[\"en\"],\"routing\":{\"prefixDefaultLocale\":false,\"redirectToDefaultLocale\":false,\"fallbackType\":\"redirect\"}}}","docs",["Map",11,12,25,26,36,37,9,47,57,58,68,69,79,80,90,91,101,102,112,113,123,124,134,135,145,146,156,157,167,168,178,179,189,190,200,201,211,212,222,223,233,234,244,245,255,256,266,267,277,278,288,289,299,300,310,311,321,322],"docs/architecture",{"id":11,"data":13,"body":22,"filePath":23,"digest":24,"deferredRender":16},{"title":14,"description":15,"editUrl":16,"head":17,"template":18,"sidebar":19,"pagefind":16,"draft":20},"Architecture","A short overview of the Secure Exec architecture, with a link to the canonical agentOS architecture docs.",true,[],"doc",{"hidden":20,"attrs":21},false,{},"import { LinkCard } from '@astrojs/starlight/components';\n\nSecure Exec runs untrusted guest code inside a fully virtualized VM whose kernel services every guest syscall. At a glance:\n\n- **Kernel-owned VM**: A kernel owns the virtual filesystem, process table, and socket table, plus pipes, PTYs, permission policy, and DNS. There is no real host filesystem, host socket, or host process available to the guest.\n- **Guest runs in an executor**: Guest JavaScript runs in a V8 isolate and other guest code runs in a WASM executor, holding no real host capabilities of their own.\n- **Sidecar mediates every syscall**: A trusted sidecar is the enforcement point. Every guest syscall flows through kernel-owned paths it controls, where policy and limits are checked.\n- **Normal Linux semantics**: The VM presents POSIX-like behavior to guest programs, so normal tools run unmodified while staying fully virtualized.\n\n## Full reference\n\nThe canonical, in-depth architecture reference, including packages, crates, trust boundaries, and syscall paths, is owned by agentOS.\n\n\u003CLinkCard\n title=\"agentOS: Architecture\"\n href=\"https://agentos-sdk.dev/docs/architecture\"\n description=\"The complete architecture reference, including components, trust boundary, and syscall paths.\"\n/>","src/content/docs/docs/architecture.mdx","75746a9343397eb7","docs/benchmarks",{"id":25,"data":27,"body":33,"filePath":34,"digest":35,"deferredRender":16},{"title":28,"description":29,"editUrl":16,"head":30,"template":18,"sidebar":31,"pagefind":16,"draft":20},"Benchmarks","Cold start, warm execution, and reuse fast-path measurements for the Secure Exec SDK.",[],{"hidden":20,"attrs":32},{},"import { Aside } from '@astrojs/starlight/components';\n\nThese numbers measure the public `secure-exec` SDK paths that consumers actually use. The cold start matrix (`packages/benchmarks/coldstart.bench.ts`) times the full journey from booting a runtime to running guest code, and compares three ways of provisioning a runtime against how much you can reuse.\n\n\u003CAside type=\"note\">Numbers below are a full run from June 19, 2026 on the hardware listed under [Methodology](#methodology). They are indicative at this sample count (5 iterations + 1 warmup), not statistically tight. Reproduce them with the commands in [Running the benchmarks](#running-the-benchmarks).\u003C/Aside>\n\n## Scenarios\n\n- **owned-sidecar**: `NodeRuntime.create()` boots a fresh sidecar process for each runtime. This is the default, fully isolated path (see [Process Isolation](/docs/architecture)).\n- **shared-sidecar**: one sidecar process is created once and reused across many runtimes, instead of spawning a fresh sidecar per runtime. Sidecar setup is measured separately and excluded from cold start, so this isolates the per-runtime cost. (Sharing a sidecar is a reuse fast path: spawn one `Sidecar` and pass it to `NodeRuntime.create({ sidecar })`, instead of the default `NodeRuntime.create()` path that owns a fresh sidecar per runtime.)\n- **resident-runner**: a shared sidecar plus a resident runner, so repeated small snippets reuse one live guest Node process instead of starting a new one each time.\n\n## Cold vs warm\n\nEach scenario reports two latencies:\n\n- **Cold**: provisioning the runtime and running the first guest snippet end to end.\n- **Warm**: running a second snippet on the same runtime, after it is already up.\n\nA single sequential runtime (batch size 1) gives the cleanest picture:\n\n| Scenario | Cold mean | Cold p50 | Warm mean | Warm p50 |\n| --- | ---: | ---: | ---: | ---: |\n| owned-sidecar | 772.88ms | 771.96ms | 452.68ms | 452.37ms |\n| shared-sidecar | 774.17ms | 774.50ms | 457.19ms | 452.75ms |\n| resident-runner | 351.00ms | 349.56ms | 1.27ms | 1.27ms |\n\nThe headline result is the resident runner: once the live guest process exists, a warm snippet runs in about **1.3ms**, roughly 350x faster than a warm execution that still has to stand up a guest process. Owned and shared sidecars cost about the same per runtime when run sequentially, because the sidecar process itself is cheap to spawn (around 3ms); sharing it mainly matters under concurrency.\n\n## Where the cold-start time goes\n\nBreaking down a single owned-sidecar cold start (batch 1, sequential, p50 per phase):\n\n| Phase | p50 |\n| --- | ---: |\n| sidecar_spawn | 2.78ms |\n| session_open | 2.34ms |\n| vm_create | 1.36ms |\n| vm_configure | 0.17ms |\n| runtime_mount_node | 2.71ms |\n| runtime_mount_wasm | 172.95ms |\n| runtime_create_total | 176.30ms |\n| first_exec | 596.26ms |\n| warm_exec | 452.37ms |\n\nTwo phases dominate: mounting the WASM command set (about 173ms) and the first guest execution (about 596ms, which includes bringing up the guest Node runtime). Spawning the sidecar, opening a session, and creating the VM together cost only a few milliseconds. This is why the resident runner wins so decisively: it pays the first-exec cost once and then reuses the live process.\n\n## Concurrency\n\nThe matrix also runs each scenario at larger batch sizes, both sequentially and concurrently (up to the host concurrency cap). Cold mean latency by batch size:\n\n| Scenario | Mode | b=1 | b=10 | b=50 | b=100 | b=200 |\n| --- | --- | ---: | ---: | ---: | ---: | ---: |\n| owned-sidecar | sequential | 772.88ms | 780.07ms | 777.49ms | 777.89ms | 778.28ms |\n| owned-sidecar | concurrent | 776.22ms | 1000.39ms | 1041.81ms | 1041.19ms | 1044.03ms |\n| shared-sidecar | sequential | 774.17ms | 627.58ms | 610.76ms | 619.24ms | 616.20ms |\n| shared-sidecar | concurrent | 775.66ms | 3493.51ms | 3197.96ms | 3187.99ms | 3235.65ms |\n| resident-runner | sequential | 351.00ms | 202.61ms | 187.92ms | 186.10ms | 189.76ms |\n| resident-runner | concurrent | 347.91ms | 205.00ms | 187.45ms | 187.07ms | 191.33ms |\n\nTakeaways:\n\n- **owned-sidecar** holds flat when sequential. Run concurrently, per-runtime cold time rises to about 1040ms as many runtimes mount their WASM command sets at once and contend for CPU. Each runtime still has its own sidecar, so they make progress in parallel.\n- **shared-sidecar** is efficient sequentially (around 610ms once the shared sidecar is warm) but degrades sharply under concurrency (3000ms or more), because one sidecar process serializes the heavy concurrent mount and first-exec work. Share a sidecar when work arrives sequentially or at low concurrency, not for bursty parallel fan-out.\n- **resident-runner** improves with batch size as the one-time runner creation amortizes, settling around 187ms cold and about 1.3ms warm regardless of mode.\n\n## Choosing a strategy\n\n- Need strong isolation and unpredictable, bursty load: use **owned-sidecar** (the default). Each runtime is its own crash and resource domain.\n- Running many short tasks back to back where a shared failure domain is acceptable: a **shared-sidecar** amortizes setup.\n- Running the same kind of small snippet over and over (for example an evaluation loop): a **resident-runner** turns a roughly 450ms warm execution into a roughly 1.3ms one.\n\nSee [Process Isolation](/docs/architecture) for what each of these shares and isolates.\n\n## Methodology\n\n```text\nCPU: 12th Gen Intel(R) Core(TM) i7-12700KF\nCores: 20 | Max concurrency: 16 | Max live runtimes: 8\nRAM: 62.6 GB | Node: v24.13.0\nIterations: 5 (+ 1 warmup)\nBatch sizes: 1, 10, 50, 100, 200\nScenarios: owned-sidecar, shared-sidecar, resident-runner\nSidecar: release build of secure-exec-sidecar\n```\n\nCold start is wall time from the start of runtime provisioning through the first guest execution. Warm is a second execution on the already-running runtime. For shared-sidecar, the one-time sidecar setup (around 4ms to 5ms) is measured separately and excluded from the per-runtime cold number. Phase timings (`sidecar_spawn`, `session_open`, `vm_create`, `runtime_mount_wasm`, `first_exec`, and the resident-runner phases) are recorded in the machine-readable JSON output.\n\n## Running the benchmarks\n\nBuild a release sidecar first for meaningful timings:\n\n```bash\ncargo build --release -p secure-exec-sidecar\n```\n\nRun the full suite:\n\n```bash\npnpm --dir packages/benchmarks bench\n```\n\nRun only the cold start matrix:\n\n```bash\nSECURE_EXEC_SIDECAR_BIN=\"$PWD/target/release/secure-exec-sidecar\" \\\n pnpm --silent --dir packages/benchmarks bench:coldstart \\\n > packages/benchmarks/results/coldstart-local.json \\\n 2> packages/benchmarks/results/coldstart-local.log\n```\n\nA quick smoke run keeps it to one iteration:\n\n```bash\nBENCH_BATCH_SIZES=1 \\\nBENCH_ITERATIONS=1 \\\nBENCH_WARMUP=0 \\\nBENCH_SCENARIOS=owned-sidecar,shared-sidecar,resident-runner \\\nSECURE_EXEC_SIDECAR_BIN=\"$PWD/target/release/secure-exec-sidecar\" \\\n pnpm --silent --dir packages/benchmarks bench:coldstart\n```","src/content/docs/docs/benchmarks.mdx","69ffe1ad5d2c20f8","docs/crash-course",{"id":36,"data":38,"body":44,"filePath":45,"digest":46,"deferredRender":16},{"title":39,"description":40,"editUrl":16,"head":41,"template":18,"sidebar":42,"pagefind":16,"draft":20},"Crash Course","A fast tour of Secure Exec: install, run code, capture output, and the core SDK concepts.",[],{"hidden":20,"attrs":43},{},"import { Tabs, TabItem } from '@astrojs/starlight/components';\n\nThis is a fast, guided walk through the essentials: install the SDK, boot a\nruntime, run guest code, and capture its output. By the end you will understand\nthe core loop and know where to go for more.\n\n`NodeRuntime` is the entry point: it boots a virtualized VM and runs guest JavaScript end to end, secure by default (no host filesystem, network, or process access until you allow it) and with every `create()` option optional so you can start with zero setup.\n\nFor exact signatures and option shapes, see the\n[TypeScript SDK reference](/docs/sdks/typescript).\n\n## Install\n\n\u003CTabs>\n \u003CTabItem label=\"npm\">\n ```bash\n npm install secure-exec\n ```\n \u003C/TabItem>\n \u003CTabItem label=\"bun\">\n ```bash\n bun add secure-exec\n ```\n \u003C/TabItem>\n \u003CTabItem label=\"pnpm\">\n ```bash\n pnpm add secure-exec\n ```\n \u003C/TabItem>\n \u003CTabItem label=\"yarn\">\n ```bash\n yarn add secure-exec\n ```\n \u003C/TabItem>\n\u003C/Tabs>\n\n## Your first run\n\nThe core loop is always the same: create a runtime, run code, dispose it.\n\n```ts\nimport { NodeRuntime } from \"secure-exec\";\n\nconst rt = await NodeRuntime.create();\ntry {\n const { stdout } = await rt.exec(\"console.log('hi', 1 + 1)\");\n console.log(stdout); // \"hi 2\\n\"\n} finally {\n await rt.dispose();\n}\n```\n\n- **`NodeRuntime.create()`**: boots a fresh VM. Reuse one runtime across many runs.\n- **`rt.exec(code)`**: runs guest code as an ES module.\n- **`rt.dispose()`**: releases the VM and its sidecar. Always call it when done.\n\n*[See Full Example](https://github.com/rivet-dev/secure-exec/tree/main/examples/docs/sdk-overview)*\n\n## Capture output\n\n`exec()` returns the streams and exit code from the run.\n\n```ts\nconst { stdout, stderr, exitCode } = await rt.exec(`\n console.log(\"to stdout\");\n console.error(\"to stderr\");\n`);\nconsole.log(exitCode); // 0\n```\n\n`exitCode` is `0` on a clean exit and non-zero if the guest threw or was killed.\n\nRead more about [Output Capture](/docs/features/output-capture).\n\n## Return a value\n\nUse `run\u003CT>()` when you want a typed value back instead of parsing stdout. The\nguest returns it with `globalThis.__return(value)`.\n\n```ts\nconst { value } = await rt.run\u003C{ sum: number }>(`\n globalThis.__return({ sum: 2 + 40 });\n`);\nconsole.log(value?.sum); // 42\n```\n\nRead more about [Executing Code](/docs/features/executing-code).\n\n## Set a timeout\n\nPass a `timeout` so a runaway guest cannot run forever. The VM kills the process\nwhen the budget elapses.\n\n```ts\nconst result = await rt.exec(`while (true) {}`, { timeout: 1000 });\nconsole.log(result.exitCode); // non-zero: the guest was killed\n```\n\nRead more about [Resource Limits](/docs/features/resource-limits).\n\n## Where to go next\n\nYou now know the core loop. Each feature builds on it:\n\n- **[Executing Code](/docs/features/executing-code)**: `exec`, `run`, modules, and inputs.\n- **[Child Processes](/docs/features/child-processes)**: `spawn()` for long-running guest programs.\n- **[Resident Runner](/docs/features/resident-runner)**: keep a guest process alive for fast repeated runs.\n- **[Filesystem](/docs/features/filesystem)**: read, write, and seed the virtualized VFS.\n- **[NPM & Module Loading](/docs/features/module-loading)**: resolve real npm packages inside the VM.\n- **[Networking](/docs/features/networking)**: guest `fetch`, sockets, and driving HTTP into a guest server.\n- **[Bindings](/docs/features/bindings)**: expose curated host functions to guest code.\n- **[Permissions](/docs/features/permissions)**: grant network and other access over the secure default.\n- **[Runtime & Platform](/docs/features/runtime-platform)**: shape the env, cwd, and platform the guest sees.\n- **[TypeScript](/docs/features/typescript)**: compile and type-check inside the sandbox.","src/content/docs/docs/crash-course.mdx","d957da03c617dc62",{"id":9,"data":48,"body":54,"filePath":55,"digest":56,"deferredRender":16},{"title":49,"description":50,"editUrl":16,"head":51,"tableOfContents":20,"template":18,"sidebar":52,"pagefind":16,"draft":20},"Introduction","Secure Exec: a fully virtualized runtime for executing untrusted code with zero host escapes.",[],{"hidden":20,"attrs":53},{},"import DocsLanding from '@rivet-dev/docs-theme/components/DocsLanding.astro';\n\n\u003CDocsLanding />","src/content/docs/docs/index.mdx","a8dfe24bc5f05d6f","docs/nodejs-compatibility",{"id":57,"data":59,"body":65,"filePath":66,"digest":67,"deferredRender":16},{"title":60,"description":61,"editUrl":16,"head":62,"template":18,"sidebar":63,"pagefind":16,"draft":20},"Node.js Compatibility","Which node builtins guest code can import in Secure Exec, and how each one is backed.",[],{"hidden":20,"attrs":64},{},"import { Aside } from '@astrojs/starlight/components';\n\nGuest code in Secure Exec runs as Node.js. It never touches the host runtime: every guest `import`/`require` of a `node:` builtin resolves to a kernel-backed bridge or an in-isolate polyfill, never the real host module. This page describes which builtins are available and how each one is implemented.\n\nThe guest reports itself as Node `v22.0.0` (`process.version`).\n\n## How builtins are backed\n\nThere are three ways a builtin is provided to guest code:\n\n- **Bridge.** A kernel-backed implementation. Calls route through the kernel VFS, socket table, process table, DNS resolver, or host entropy. This is how `fs`, `net`, `http`, `child_process`, `dns`, `os`, and `crypto` reach virtualized resources while staying inside the isolation boundary.\n- **Polyfill.** A pure-JavaScript implementation from `node-stdlib-browser` (for example `path`, `events`, `util`, `stream`, `zlib`). These need no host access; they run entirely inside the V8 isolate.\n- **Denied.** The module is intentionally unavailable. Importing it throws an error with code `ERR_ACCESS_DENIED`.\n\nThe canonical inventory lives in `crates/execution/assets/polyfill-registry.json`.\n\n\u003CAside type=\"note\">A guest never falls through to a real host builtin. Anything not bridged or polyfilled is denied, so there is no path where guest code reaches the host runtime.\u003C/Aside>\n\n## Bridge-backed builtins\n\nThese route through the kernel and present normal Linux/Node semantics over virtualized resources.\n\n| Module | Backed by |\n| --- | --- |\n| `fs`, `fs/promises` | Kernel VFS. File and directory operations, fds, `createReadStream`/`createWriteStream`, metadata, symlinks. `watch`/`watchFile` are guest-side polling wrappers. |\n| `child_process` | Kernel process table. `spawn`, `exec`, `execFile`, `spawnSync`, `execSync`, `execFileSync` (and the sync variants) run kernel-managed processes. See [Child Processes](/docs/features/child-processes). |\n| `net` | Kernel socket table. TCP client and server sockets, plus Unix sockets. |\n| `dns` | Kernel DNS resolver (`lookup`, `resolve*`, and the `dns/promises` surface). |\n| `http`, `https`, `http2` | Built on the kernel socket path. `request`, `get`, `createServer`, agents with connection pooling. |\n| `tls` | Layered on the kernel `net` polyfill. |\n| `os` | VM-scoped values (platform, arch, hostname, CPU/memory, user info, `os.constants`). |\n| `crypto` | Host entropy and crypto bridges: `getRandomValues`, `randomUUID`, `randomBytes`, `createHash`, `createHmac`, cipher/decipher, scrypt, and `crypto.subtle` (WebCrypto). |\n| `process` | Virtualized `process` global: env (permission-gated), `cwd`/`chdir`, signals, timers, stdio, `umask`. |\n| `module` | `createRequire`, `Module` basics, builtin resolution, `Module.builtinModules`. |\n| `console` | Bridge shim with circular-safe formatting. Output is captured into the `stdout`/`stderr` result fields and can also be streamed via the `onStdout`/`onStderr` hooks on `exec`/`run`/`spawn`. |\n| `dgram` | Kernel socket table (UDP). |\n| `perf_hooks`, `diagnostics_channel`, `async_hooks` | Bridge-backed compatibility surfaces. |\n| `worker_threads` | Compatibility shim: `isMainThread` and inert ports for feature detection. Real worker threads are not spawned. |\n| `vm` | Compatibility shim: `Script`, `createContext`, `isContext`, `runInNewContext`, `runInThisContext`. |\n| `v8` | Compatibility shim for safe inspection/serialization helpers. |\n| `tty` | `isatty` plus `ReadStream`/`WriteStream` compatibility constructors. |\n| `readline`, `sqlite` | Bridge-backed compatibility surfaces. |\n| `timers`, `timers/promises` | `setTimeout`, `setInterval`, `setImmediate`, and promise variants. |\n| `stream/web`, `stream/consumers`, `stream/promises` | Web Streams and stream helper subpaths. |\n\nNetwork builtins (`net`, `dgram`, `dns`, `http`, `https`, `http2`, `tls`) are subject to the per-runtime permission policy, which **denies network access by default**. Operations fail until you opt in. See [Permissions](/docs/features/permissions).\n\n## Polyfilled builtins\n\nPure-JavaScript implementations from `node-stdlib-browser`, running inside the isolate. They support default and named ESM imports.\n\n| Module | Polyfill |\n| --- | --- |\n| `path`, `path/posix`, `path/win32` | `path-browserify` |\n| `buffer` | `buffer` (also re-exports `Blob`/`File`) |\n| `events` | `events` |\n| `stream` | `readable-stream` |\n| `util`, `util/types` | node-stdlib-browser |\n| `assert` | node-stdlib-browser |\n| `url` | node-stdlib-browser shims |\n| `querystring` | node-stdlib-browser |\n| `string_decoder` | node-stdlib-browser |\n| `zlib` | node-stdlib-browser |\n| `punycode` | node-stdlib-browser |\n| `constants` | `constants-browserify` (`os.constants` stays available via `os`) |\n| `console`, `timers` | node-stdlib-browser base, with bridge wiring for stdio and the kernel clock |\n| `sys` | alias of `util` |\n\n## Denied builtins\n\nImporting any of these throws an error with code `ERR_ACCESS_DENIED`:\n\n`cluster`, `domain`, `inspector`, `repl`, `trace_events`, `wasi`.\n\n## Global APIs\n\nWeb platform globals expected by modern npm packages are provided in the isolate, including `fetch`, `Headers`, `Request`, and `Response`. Guest `fetch()` runs through undici inside the V8 isolate and then through the kernel socket table, so it obeys the same network permissions as the `http`/`net` builtins. `TextEncoder`/`TextDecoder`, `Buffer`, `URL`/`URLSearchParams`, `Blob`/`File`, `FormData`, `AbortController`/`AbortSignal`, `structuredClone`, and `performance` are also available.\n\nWebAssembly is enabled inside the isolate (`WebAssembly.Module`, `WebAssembly.Instance`, `WebAssembly.instantiate*`), so packages that ship `.wasm` work. Compilation stays inside the isolate and does not cross the isolation boundary.\n\n## Restricting the builtin surface\n\nThe builtin surface can be narrowed through the [platform / `allowedBuiltins` config](/docs/features/runtime-platform); anything excluded becomes a denied builtin (`ERR_ACCESS_DENIED`).\n\n\u003CAside type=\"caution\">This config (`CreateVmConfig.jsRuntime`) rides the wire `CreateVmConfig` and is not currently exposed through `NodeRuntime.create()`. See [Runtime Platform](/docs/features/runtime-platform) for the platform ladder and [TypeScript SDK](/docs/sdks/typescript) for the config shape.\u003C/Aside>\n\n## Logging behavior\n\n- `console.log`/`warn`/`error` serialize arguments with circular-safe, bounded formatting.\n- `exec()` and `run()` buffer guest output and return it as the `stdout` and `stderr` strings on the result.\n- To observe output incrementally, pass the `onStdout`/`onStderr` hooks, which receive raw `Uint8Array` chunks in emission order; the full strings are still returned when the run ends.\n\nSee [Output Capture](/docs/features/output-capture) for details.\n\n## TypeScript\n\nThe core runtime executes JavaScript. For sandboxed TypeScript usage, see [TypeScript](/docs/features/typescript).\n\n## Example\n\nImport a mix of bridge-backed and polyfilled builtins from guest code:\n\n```ts\nimport { NodeRuntime } from \"secure-exec\";\n\nconst rt = await NodeRuntime.create();\n\ntry {\n const { stdout } = await rt.exec(`\n import path from \"node:path\";\n import { createHash } from \"node:crypto\";\n import { writeFileSync, readFileSync } from \"node:fs\";\n\n const file = path.join(\"/tmp\", \"note.txt\");\n writeFileSync(file, \"hello\");\n\n const digest = createHash(\"sha256\")\n .update(readFileSync(file))\n .digest(\"hex\");\n\n console.log(digest);\n `);\n\n console.log(stdout.trim());\n} finally {\n await rt.dispose();\n}\n```\n\n## See also\n\n- **Module loading and resolution**: how ESM/CJS, the `node_modules` walk, and unmodified npm packages resolve over the virtual filesystem lives in [NPM & Module Loading](/docs/features/module-loading).\n- **Output capture**: how `stdout`/`stderr` are buffered and streamed is documented in [Output Capture](/docs/features/output-capture).","src/content/docs/docs/nodejs-compatibility.mdx","ff6c1ee286812704","docs/quickstart",{"id":68,"data":70,"body":76,"filePath":77,"digest":78,"deferredRender":16},{"title":71,"description":72,"editUrl":16,"head":73,"template":18,"sidebar":74,"pagefind":16,"draft":20},"Quickstart","Get Secure Exec running in a few minutes.",[],{"hidden":20,"attrs":75},{},"import { Tabs, TabItem, Steps, CardGrid, LinkCard } from '@astrojs/starlight/components';\n\n\u003CSteps>\n1. **Install**\n\n \u003CTabs>\n \u003CTabItem label=\"npm\">\n ```bash\n npm install secure-exec\n ```\n \u003C/TabItem>\n \u003CTabItem label=\"bun\">\n ```bash\n bun add secure-exec\n ```\n \u003C/TabItem>\n \u003CTabItem label=\"pnpm\">\n ```bash\n pnpm add secure-exec\n ```\n \u003C/TabItem>\n \u003CTabItem label=\"yarn\">\n ```bash\n yarn add secure-exec\n ```\n \u003C/TabItem>\n \u003C/Tabs>\n\n2. **Create a runtime**\n\n `NodeRuntime.create()` boots a fully virtualized VM behind the native sidecar. Guest code runs inside the kernel isolation boundary with no host escapes. All options are optional: `cwd` defaults to `/workspace`, and permissions default to a secure policy that denies network access (see step 4).\n\n ```ts\n import { NodeRuntime } from \"secure-exec\";\n\n const runtime = await NodeRuntime.create();\n ```\n\n3. **Run code**\n\n Use `run()` when you want a JSON value back; the guest calls `globalThis.__return(value)` to set it. Use `exec()` when you care about side effects and want to capture `stdout`/`stderr`/`exitCode`. Guest code runs as an ES module, so `import` and top-level `await` both work.\n\n \u003CTabs>\n \u003CTabItem label=\"Return a value\">\n ```ts\n import { NodeRuntime } from \"secure-exec\";\n\n // Boot a fully virtualized runtime. Guest code runs inside the kernel\n // isolation boundary - no host escapes.\n const runtime = await NodeRuntime.create();\n\n try {\n // run() executes guest JavaScript as an ES module and returns the value the\n // guest passes to globalThis.__return(). stdout/stderr are captured too.\n const result = await runtime.run\u003C{ message: string; sum: number }>(`\n console.log(\"hello from secure-exec\");\n __return({ message: \"hello from secure-exec\", sum: 1 + 2 });\n `);\n\n console.log(\"stdout:\", JSON.stringify(result.stdout.trim()));\n console.log(\"value:\", result.value);\n console.log(\"exitCode:\", result.exitCode);\n } finally {\n // Tear down the VM and release the sidecar.\n await runtime.dispose();\n }\n ```\n \u003C/TabItem>\n\n \u003CTabItem label=\"Capture output\">\n ```ts\n import { NodeRuntime } from \"secure-exec\";\n\n const runtime = await NodeRuntime.create();\n\n try {\n // exec() runs guest code for its side effects and captures the streams.\n const result = await runtime.exec(`\n console.log(\"hello from secure-exec\");\n console.error(\"this goes to stderr\");\n `);\n\n console.log(\"stdout:\", JSON.stringify(result.stdout.trim()));\n console.log(\"stderr:\", JSON.stringify(result.stderr.trim()));\n console.log(\"exitCode:\", result.exitCode);\n } finally {\n await runtime.dispose();\n }\n ```\n \u003C/TabItem>\n \u003C/Tabs>\n\n *[See Full Example](https://github.com/rivet-dev/secure-exec/tree/main/examples/docs/quickstart)*\n\n4. **Configure permissions (optional)**\n\n Guest code is **deny-by-default** for network access. Pass a `permissions` policy to `NodeRuntime.create()` to opt in; it merges over the secure default, so you only specify what you want to change:\n\n ```ts\n const runtime = await NodeRuntime.create({\n permissions: { network: \"allow\" },\n });\n ```\n\n See [Permissions](/docs/features/permissions) for the full scope list and merge semantics.\n\u003C/Steps>\n\n## Next steps\n\n\u003CCardGrid>\n \u003CLinkCard title=\"Crash Course\" href=\"/docs/crash-course\" description=\"A fast tour of the essential SDK API and core concepts.\" />\n \u003CLinkCard title=\"Permissions\" href=\"/docs/features/permissions\" description=\"Control filesystem, network, and process access.\" />\n\u003C/CardGrid>","src/content/docs/docs/quickstart.mdx","d7c55552abab83cb","docs/security-model",{"id":79,"data":81,"body":87,"filePath":88,"digest":89,"deferredRender":16},{"title":82,"description":83,"editUrl":16,"head":84,"template":18,"sidebar":85,"pagefind":16,"draft":20},"Security Model","A short overview of Secure Exec isolation and trust, with a link to the canonical agentOS security model.",[],{"hidden":20,"attrs":86},{},"import { LinkCard } from '@astrojs/starlight/components';\n\nSecure Exec runs guest code inside a fully virtualized VM so untrusted code stays contained. At a glance:\n\n- **V8 isolate boundary**: Guest JavaScript runs in a V8 isolate inside the kernel. It never spawns a real host process, touches the real host filesystem, or opens a real host socket.\n- **Sidecar enforces**: A trusted sidecar owns the kernel, VFS, socket table, and permission policy. Every guest syscall is mediated and checked there, not on the host.\n- **Executor is untrusted**: The code you submit for execution is treated as actively hostile. How it reached the executor never makes it trusted.\n- **Secure defaults**: The network is deny-by-default; filesystem, child processes, process info, and env are enabled so normal programs run. Resource and timing limits bound runaway or hostile code.\n\n## Full reference\n\nThe canonical threat model, trust boundaries, and detailed enforcement guarantees are owned by agentOS.\n\n\u003CLinkCard\n title=\"agentOS: Security Model\"\n href=\"https://agentos-sdk.dev/docs/security-model\"\n description=\"The complete trust model, threat model, and enforcement details.\"\n/>","src/content/docs/docs/security-model.mdx","30b9a6c259efa482","docs/comparison/cloudflare-workers",{"id":90,"data":92,"body":98,"filePath":99,"digest":100,"deferredRender":16},{"title":93,"description":94,"editUrl":16,"head":95,"template":18,"sidebar":96,"pagefind":16,"draft":20},"Secure Exec vs Cloudflare Workers","How Secure Exec and Cloudflare Workers differ in isolation model, permissions, networking, and Node.js compatibility.",[],{"hidden":20,"attrs":97},{},"import { Aside, LinkCard } from '@astrojs/starlight/components';\n\nSecure Exec and Cloudflare Workers both run untrusted JavaScript inside V8, but they solve different problems. Workers is a managed, multi-tenant edge platform: you deploy code and Cloudflare runs it for you across its network. Secure Exec is a library you embed in your own application to run guest code locally inside a fully virtualized VM that you control. This page focuses on how the two differ in isolation, permissions, networking, and Node.js surface.\n\n## At a glance\n\n| | Secure Exec | Cloudflare Workers |\n| --- | --- | --- |\n| **Form factor** | Library you embed (`secure-exec`), runs where your app runs | Managed edge platform you deploy to |\n| **Isolation unit** | Per runtime: each `NodeRuntime.create()` is its own VM and OS process | Per Worker isolate, scheduled by Cloudflare |\n| **Guest runtime** | V8 isolate inside a virtualized POSIX kernel (filesystem, processes, sockets, PTYs) | V8 isolate with the `workerd` runtime |\n| **Permissions** | Deny-by-default capability policy you configure per runtime | Platform-managed; no per-call capability policy |\n| **Subprocesses** | Real `node:child_process` against kernel-managed processes | Not available |\n| **Filesystem** | Full virtualized filesystem per runtime | Limited in-memory `node:fs` surface, ephemeral |\n| **You operate it** | Yes (your process, your machine) | No (Cloudflare operates it) |\n\n## Isolation model\n\nThis is the most important difference, and the easiest one to misstate.\n\nCloudflare Workers isolates code dynamically. Cloudflare's runtime schedules many Workers into a pool of V8 isolates and can move work between them, with platform-level mitigations (such as I/O-gated clock coarsening) layered on to defend against side-channel attacks across that shared infrastructure.\n\nSecure Exec isolates code statically, one boundary per runtime. Every `NodeRuntime.create()` boots a fully virtualized VM backed by its own sidecar process. Two runtimes share nothing: not the filesystem, not globals, not module state, and not crash fate. Secure Exec does not reassign guest code between processes at runtime, and it does not claim Cloudflare-style dynamic, cross-tenant isolate scheduling. You decide the blast radius by deciding how many runtimes to create and what to put in each one.\n\nWithin a single runtime, every `exec()` or `run()` call runs in a fresh guest process, so in-memory state from one run does not leak into the next.\n\n\u003CLinkCard\n\ttitle=\"Process Isolation\"\n\tdescription=\"How runtimes and runs are isolated, and how to choose granularity.\"\n\thref=\"/docs/architecture\"\n/>\n\nThe practical consequence: with Workers you trust Cloudflare's platform to keep tenants apart. With Secure Exec you get a hard, statically-defined boundary per runtime that you place yourself, which is well suited to running one tenant or one task per runtime and disposing it when finished.\n\n## Permissions\n\nCloudflare Workers does not expose a per-invocation capability policy. What a Worker can reach is governed by its bindings and platform configuration.\n\nSecure Exec applies a deny-by-default capability policy per runtime. Network access is denied until you opt in; the virtualized filesystem, child-process, process, and env scopes are enabled so programs can run at all (the guest only ever sees the VM, never the real host). You tighten or widen any scope when you create the runtime.\n\n```ts\nimport { NodeRuntime } from \"secure-exec\";\n\n// Default: no network access. Filesystem and processes are virtualized.\nconst sandboxed = await NodeRuntime.create();\n\n// Opt into network access while keeping the other defaults.\nconst networked = await NodeRuntime.create({\n permissions: { network: \"allow\" },\n});\n```\n\n\u003CAside type=\"note\">The permission policy is merged over a secure default, so a partial policy like `{ network: \"allow\" }` works. See [Permissions](/docs/features/permissions) for rule-set syntax to gate individual scopes.\u003C/Aside>\n\n## Networking\n\nInside the VM, guest `fetch()` runs through undici in the V8 isolate and then through the kernel's socket table, gated by the network permission. Guest code can also bind ports inside the VM: Secure Exec exposes `findListener()` and `waitForListener()` so the host can detect when a guest process starts listening (for example, to wait for an in-VM HTTP server before sending it a request).\n\nFrom the host side, `rt.fetch(port, input)` drives an HTTP request into a guest server listening inside the VM and reads the response back. The request never leaves the VM (it connects to the guest's loopback listener through the kernel socket table), so it works even when guest network egress is denied.\n\nCloudflare Workers provides outbound `fetch()` and a Sockets API for outbound TCP/TLS, but a Worker does not listen on a port the way a normal server does; it responds to incoming requests routed by the platform.\n\n```ts\nimport { NodeRuntime } from \"secure-exec\";\n\nconst rt = await NodeRuntime.create();\ntry {\n // Start a long-running guest HTTP server and get a live handle back.\n const server = await rt.spawn(`\n import http from \"node:http\";\n http.createServer((_req, res) => res.end(\"ok\")).listen(3000);\n `);\n\n // Block until the listener is up, then drive a request into it from the host.\n await rt.waitForListener({ port: 3000 });\n const res = await rt.fetch(3000, { path: \"/\" });\n console.log(res.status, res.body); // 200 ok\n\n server.kill();\n await server.wait();\n} finally {\n await rt.dispose();\n}\n```\n\n## Subprocesses and the POSIX surface\n\nSecure Exec presents a virtualized POSIX environment. Guest code can use `node:child_process` to spawn commands that exist inside the VM (such as `sh` and the mounted coreutils), and every child is a kernel-managed process, never a real host process. The host can also start a long-running guest program and drive it with `rt.spawn()`.\n\nCloudflare Workers has no subprocess model. There is no `child_process`, no process table, and no shell.\n\n\u003CLinkCard\n\ttitle=\"Child Processes\"\n\tdescription=\"Spawn kernel-managed processes from guest code, or drive a long-running guest program from the host.\"\n\thref=\"/docs/features/child-processes\"\n/>\n\n## Node.js compatibility\n\nBoth runtimes aim to present Node.js semantics on top of V8, and both implement a large subset of the Node.js standard library. The character of the gaps differs:\n\n- **Secure Exec** is backed by a real virtualized kernel, so capabilities that need an OS, a full filesystem, real child processes, sockets that listen, and a process table, are first-class. Pure-JS builtins are provided through `node-stdlib-browser`, and kernel-backed modules (such as `fs`, `net`, `child_process`, `dns`, `http`, `os`) are wired through the bridge to the kernel.\n- **Cloudflare Workers** provides Node.js compatibility through the `nodejs_compat` flag on top of `workerd`. Its filesystem is a limited in-memory surface, there is no subprocess support, and listening servers are replaced by the request/response handler model. In exchange it ships a comprehensive native `node:crypto` and Web Crypto surface and platform-native logging.\n\n\u003CAside type=\"note\">Module support evolves on both sides. Treat the points above as the shape of the difference (kernel-backed POSIX vs managed edge isolate), not a frozen feature matrix. Verify a specific module against the current behavior of whichever runtime you target.\u003C/Aside>\n\n## When to choose which\n\nChoose **Cloudflare Workers** when you want a managed, globally distributed platform to deploy your own trusted code to, with the operations handled for you.\n\nChoose **Secure Exec** when you need to run untrusted or AI-generated code inside your own application with a hard, self-placed isolation boundary, a real virtualized filesystem and process model, and a capability policy you control. One runtime per tenant or per task gives you a clean blast radius you can dispose on demand.\n\n\u003CLinkCard\n\ttitle=\"Process Isolation\"\n\tdescription=\"The isolation model in depth, plus how to pick isolation granularity.\"\n\thref=\"/docs/architecture\"\n/>","src/content/docs/docs/comparison/cloudflare-workers.mdx","e9e161e5f668b03b","docs/comparison/isolated-vm",{"id":101,"data":103,"body":109,"filePath":110,"digest":111,"deferredRender":16},{"title":104,"description":105,"editUrl":16,"head":106,"template":18,"sidebar":107,"pagefind":16,"draft":20},"Secure Exec vs isolated-vm","How Secure Exec and isolated-vm differ in isolation surface, security confinement, performance, and developer experience.",[],{"hidden":20,"attrs":108},{},"import { Aside, LinkCard } from '@astrojs/starlight/components';\n\nBoth Secure Exec and isolated-vm run untrusted JavaScript inside V8 isolates, but they operate at different layers. isolated-vm is a low-level npm library that exposes a bare V8 isolate with manual value marshaling and no system surface. Secure Exec wraps V8 isolates in a full virtualized kernel: a POSIX-like VFS, process table, socket table, permission policy, and resource limits. This page focuses on the security and performance characteristics of that core runtime layer.\n\n## At a glance\n\n| | Secure Exec | isolated-vm |\n| --- | --- | --- |\n| **Layer** | Full virtualized runtime around V8 isolates | Bare V8 isolate primitive |\n| **System surface** | Virtualized filesystem, processes, sockets, PTYs, DNS | None (you build any surface yourself) |\n| **Host and guest data** | Normal Node/POSIX I/O through the kernel | Manual `Reference`/`Copy`/`ExternalCopy` marshaling |\n| **Permission model** | Deny-by-default capability policy per runtime | None (whatever you expose is reachable) |\n| **Network egress** | Mediated by the kernel socket table, gated by policy | None by default; any bridge you add is unmediated |\n| **Resource limits** | Per-VM CPU, memory, and other caps | Memory limit and timeout per isolate |\n| **npm / Node compat** | Real npm packages run unmodified | None (no module system, no `node:` builtins) |\n\n## Isolation boundary\n\nThe core difference is how much exists inside the boundary.\n\n- **isolated-vm** gives you a raw V8 isolate and nothing else. There is no filesystem, no network, no process model, and no globals beyond the ECMAScript spec. Anything the guest can reach, you have to inject yourself across the host/guest boundary by hand.\n- **Secure Exec** boots a fully virtualized VM per runtime. The guest sees a POSIX-like filesystem, a process table, sockets, pipes, PTYs, and DNS, all backed by a kernel that the guest can never escape. Every guest syscall is routed through kernel-owned paths.\n\nThe trade-off: isolated-vm is a primitive you assemble a sandbox out of. Secure Exec is the assembled sandbox.\n\n## Security\n\nA bare V8 isolate confines memory and CPU, but it confines nothing else, because there is nothing else inside it. The security of an isolated-vm deployment is entirely a property of the bridge code you write around it.\n\n- **What isolated-vm confines**: heap memory (per-isolate limit) and execution time (per-call timeout). It cannot leak host memory directly because the guest has no references it was not given.\n- **What you must build yourself**: every capability the guest needs (file access, network, subprocesses) is a function you expose across the boundary. Each exposed function is attack surface, and each is unmediated unless you add your own checks.\n- **What Secure Exec confines**: in addition to memory and time, it enforces a deny-by-default capability policy over filesystem, network, child-process, process, and env scopes. A denied operation fails with `EACCES`.\n- **Egress control**: guest `fetch()`, `node:http`, and raw sockets flow through the kernel socket table, so outbound traffic can be allowed, denied, or rule-matched. With isolated-vm there is no networking until you build it, and once built it is not policed.\n\n\u003CAside type=\"note\">With isolated-vm, a mistake in your marshaling layer (handing the guest a live host `Reference`, or an injected function that does unchecked I/O) is a sandbox escape. Secure Exec moves that boundary into a kernel so the surface the guest sees is virtualized rather than hand-wired per project.\u003C/Aside>\n\n```ts\nimport { NodeRuntime } from \"secure-exec\";\n\n// Deny-by-default: no network, filesystem and processes are virtualized.\nconst rt = await NodeRuntime.create();\n\n// Opt into network egress; it is still mediated by the kernel socket table.\nconst networked = await NodeRuntime.create({\n permissions: { network: \"allow\" },\n});\n```\n\n\u003CLinkCard\n\ttitle=\"Permissions\"\n\tdescription=\"The deny-by-default capability policy and per-scope rule sets.\"\n\thref=\"/docs/features/permissions\"\n/>\n\n## Performance\n\nBoth runtimes execute guest code in a V8 isolate, so raw JavaScript throughput is comparable. The cost differences come from what surrounds the isolate.\n\n- **isolated-vm** is the thinner layer: creating an isolate is cheap, and the dominant per-call cost is marshaling values across the host/guest boundary, which is explicit and pay-as-you-go.\n- **Secure Exec** adds syscall virtualization. Guest I/O (files, sockets, processes) is routed through the kernel, so operations that touch the system carry virtualization overhead that a bare isolate does not. Pure compute that never makes a syscall runs at isolate speed.\n- **Startup**: Secure Exec boots a virtualized VM per runtime, which is heavier than spinning up a bare isolate, but it is far lighter than a container or microVM. Reusing a live guest process drives warm execution into the low-millisecond range. See [Benchmarks](/docs/benchmarks) for measured numbers.\n\nThe summary: isolated-vm has lower overhead because it does less; Secure Exec spends that overhead on a real system surface and enforcement you would otherwise build and pay for yourself.\n\n## Developer experience\n\nThis is where the two diverge most for everyday use.\n\n- **isolated-vm**: you write to the isolate API directly. There is no module loader, no `node:` builtins, and no normal I/O. Passing data in or out means `Reference`, `Copy`, or `ExternalCopy`, and any capability is a function you wrap and inject. Running an existing npm package is not a goal of the library.\n- **Secure Exec**: the guest sees normal Linux and Node semantics. Real npm packages run unmodified, resolved over a faithfully mounted `node_modules`, and kernel-backed modules (`fs`, `net`, `child_process`, `dns`, `http`, `os`) work as they would on a real machine.\n\n```ts\nimport { NodeRuntime } from \"secure-exec\";\n\nconst rt = await NodeRuntime.create();\ntry {\n const result = await rt.run\u003Cnumber>(`\n __return(40 + 2);\n `);\n console.log(result.value); // 42\n} finally {\n await rt.dispose();\n}\n```\n\n## When to choose which\n\n| Choose | When |\n| --- | --- |\n| **isolated-vm** | You want a minimal V8 isolate primitive and intend to design and own the entire sandbox surface, capability injection, and enforcement yourself. |\n| **Secure Exec** | You want to run untrusted or AI-generated code with a virtualized filesystem, process model, and networking, plus a deny-by-default permission policy and resource limits, without hand-building the sandbox. |\n\n\u003CLinkCard\n\ttitle=\"Process Isolation\"\n\tdescription=\"The isolation model in depth, plus how to pick isolation granularity.\"\n\thref=\"/docs/architecture\"\n/>","src/content/docs/docs/comparison/isolated-vm.mdx","0d4b8a0e5ede9c7d","docs/comparison/quickjs",{"id":112,"data":114,"body":120,"filePath":121,"digest":122,"deferredRender":16},{"title":115,"description":116,"editUrl":16,"head":117,"template":18,"sidebar":118,"pagefind":16,"draft":20},"Secure Exec vs QuickJS","How Secure Exec and QuickJS differ in isolation model, performance, language coverage, and system surface.",[],{"hidden":20,"attrs":119},{},"import { Aside, LinkCard } from '@astrojs/starlight/components';\n\nSecure Exec and QuickJS both run guest JavaScript, but they sit at different layers. QuickJS is a small, embeddable JavaScript engine: you link it into a host process and call its C API. Secure Exec is a full virtualized runtime built on V8, with a kernel, virtual filesystem, and capability policy around the engine. This page focuses on the security and performance characteristics of the core runtime layer.\n\n## At a glance\n\n| | Secure Exec | QuickJS |\n| --- | --- | --- |\n| **Engine** | V8 isolate (JIT) | QuickJS bytecode interpreter |\n| **Isolation** | Virtualized VM in a dedicated sidecar process | Interpreter embedded in your host process |\n| **Performance** | JIT-compiled, high throughput | Interpreted, smaller working set |\n| **Language** | Full modern ECMAScript | Mostly ES2023, smaller engine |\n| **Node/npm** | Real npm packages and Node-compatible builtins | None built in |\n| **System surface** | Kernel: filesystem, processes, sockets, PTYs | None (host C bindings only) |\n\n## Isolation model\n\nThis is the most important difference.\n\n- **QuickJS** is an interpreter you embed directly in your host process. Guest code shares the host's address space, and anything the guest can reach is whatever your C bindings expose. There is no process boundary between guest and host by default, so isolation is entirely your responsibility to build and audit.\n- **Secure Exec** runs guest code in a V8 isolate inside a separate sidecar process, behind a virtualized POSIX kernel. Guest code never calls real Node.js builtins, never opens a real host socket, and never touches the real disk. Every syscall is routed through the kernel and checked against a deny-by-default permission policy.\n\nThe practical consequence: with QuickJS you own the entire sandbox, including the boundary, the permission checks, and the host-bindings audit surface. With Secure Exec the boundary, the kernel, and the policy enforcement are provided and run out-of-process.\n\n\u003CLinkCard\n\ttitle=\"Process Isolation\"\n\tdescription=\"How runtimes and runs are isolated, and how to choose granularity.\"\n\thref=\"/docs/architecture\"\n/>\n\n## Performance\n\nThe engines optimize for different things.\n\n- **V8 (Secure Exec)** JIT-compiles hot code to native machine code, so sustained throughput on compute-heavy guest code is far higher. The trade-off is a larger engine and a heavier per-isolate baseline.\n- **QuickJS** compiles to bytecode and interprets it. It has a very small footprint and fast startup for a single embedded instance, but interpreted execution is slower on throughput-bound work.\n\nFor Secure Exec, cold start is dominated by bringing up the guest runtime rather than provisioning infrastructure, and reusing a live guest process drives warm execution into the low-millisecond range.\n\n\u003CAside type=\"note\">Treat these as the shape of the difference (JIT throughput vs interpreter footprint), not fixed numbers. See [Benchmarks](/docs/benchmarks) for measured cold-start, warm, and reuse numbers and the methodology behind them.\u003C/Aside>\n\n## Language and ecosystem coverage\n\n- **Secure Exec** runs full modern ECMAScript on V8, the same engine as Node.js and Chrome, so language features land as V8 ships them. Real npm packages run unmodified inside the VM, resolved over a faithfully mounted `node_modules` like a real filesystem, and Node-compatible builtins are wired through the kernel.\n- **QuickJS** implements most of the ECMAScript specification in a compact engine, but it tracks the spec on its own cadence and lags V8 on newer features and edge cases. It ships no Node.js standard library and no npm resolution; any package or builtin support is something you bind in yourself.\n\n## System surface\n\n- **Secure Exec** presents a virtualized POSIX environment to guest code: a per-runtime virtual filesystem, a kernel-managed process table (with `node:child_process`), a socket table for networking, pipes, and PTYs. Guest `fetch()`, `node:http`, and raw sockets all flow through the kernel and the permission policy.\n- **QuickJS** has none of this built in. The bare engine exposes only ECMAScript globals; there is no filesystem, no process model, no networking, and no shell unless your host code adds C bindings for them. Every capability the guest needs is host surface you write and must secure.\n\n\u003CLinkCard\n\ttitle=\"Child Processes\"\n\tdescription=\"Spawn kernel-managed processes from guest code, or drive a long-running guest program from the host.\"\n\thref=\"/docs/features/child-processes\"\n/>\n\n## When to choose which\n\nChoose **QuickJS** when you need the smallest possible embeddable engine, you are running short, self-contained scripts with no system needs, and you are prepared to build and audit any sandbox boundary and host bindings yourself.\n\nChoose **Secure Exec** when you need full ECMAScript and npm compatibility, JIT throughput, and a ready-made isolation boundary with a kernel-backed filesystem, process model, networking, and a deny-by-default capability policy you control.\n\n\u003CLinkCard\n\ttitle=\"Process Isolation\"\n\tdescription=\"The isolation model in depth, plus how to pick isolation granularity.\"\n\thref=\"/docs/architecture\"\n/>","src/content/docs/docs/comparison/quickjs.mdx","836b329976c73e94","docs/comparison/sandbox",{"id":123,"data":125,"body":131,"filePath":132,"digest":133,"deferredRender":16},{"title":126,"description":127,"editUrl":16,"head":128,"template":18,"sidebar":129,"pagefind":16,"draft":20},"Secure Exec vs Container Sandbox","When to use a container sandbox versus Secure Exec for running untrusted code.",[],{"hidden":20,"attrs":130},{},"import { Aside } from '@astrojs/starlight/components';\n\nSecure Exec and container sandboxes both run untrusted code in isolation, but they sit at different points on the weight-versus-flexibility curve. Picking the right one depends on what you need to run.\n\n**Secure Exec** boots a fully virtualized VM for each runtime and runs guest JavaScript in a V8 isolate inside a dedicated sidecar process. There is no Docker daemon, no orchestrator, and no vendor account: you `npm install` the package and call `NodeRuntime.create()`. It is built for lightweight, high-fanout code execution like AI tool calls, user scripts, and plugins, where you want granular permissions and a small footprint.\n\n**Container sandboxes** (e2b, Daytona, Modal, Cloudflare Containers, and similar) spin up a full OS image with system packages, a writable disk, and the ability to run arbitrary binaries. They are built for heavyweight workloads that need a complete environment: coding agents, long-lived dev sessions, or anything that shells out to native tools.\n\n## How isolation works\n\nThe biggest difference is what the isolation boundary is made of.\n\n- **Secure Exec** runs guest code in a V8 isolate hosted by its own sidecar process. Every `NodeRuntime.create()` is a separate VM with its own virtual filesystem, process table, network policy, and crash domain. Guest code never calls real Node.js builtins, never opens a real host socket, and never touches the real disk. Every syscall is routed through the kernel. See [Process Isolation](/docs/architecture).\n- **Container sandboxes** isolate with OS-level primitives (namespaces, cgroups, or a microVM). The guest runs a real kernel and a real filesystem, so it can do anything a Linux process can, constrained by the container's configuration.\n\nSecure Exec presents normal Linux semantics to the code it runs (a POSIX-like virtual filesystem, processes, pipes, PTYs, sockets) without granting access to the host that backs them.\n\n## Comparison\n\n| Dimension | Secure Exec | Container Sandbox |\n| --- | --- | --- |\n| Isolation boundary | Virtualized VM + V8 isolate in a sidecar process | OS container or microVM |\n| Setup | `npm install secure-exec` | Vendor account or Docker host |\n| Hardware | Runs on your infrastructure | Often vendor-hosted |\n| Filesystem | Virtual, in-memory, per runtime | Full OS filesystem |\n| Network | Denied by default, opt-in per runtime | Full, or firewall rules |\n| Permissions | Per-scope policy (fs, network, childProcess, process, env, tool) | Coarse, container-level |\n| Languages | JavaScript and TypeScript (Node-compatible) | Any language the image supports |\n| Arbitrary binaries | No (guest binaries run through the VM, not the host) | Yes |\n| Crash domain | One process per runtime | One container per sandbox |\n\n## What Secure Exec gives you\n\nThese capabilities are the reason to reach for Secure Exec over a container when the workload fits in a Node-compatible runtime:\n\n- **Deny-by-default permissions.** Network egress is blocked until you opt in, and every guest syscall is checked against a per-scope policy before any host resource is touched. A denied operation fails with `EACCES`. See [Permissions](/docs/features/permissions).\n- **Virtual filesystem.** Each runtime gets its own in-memory filesystem. Guest reads and writes never reach the host disk, and two runtimes writing the same path do not collide. See [Filesystem](/docs/features/filesystem).\n- **Mediated networking.** Guest `fetch()`, `node:http`, and raw sockets all flow through the kernel socket table, so you can allow, deny, or rule-match outbound traffic. See [Networking](/docs/features/networking).\n- **Process-level isolation.** Each runtime is its own VM and its own crash domain, and each `exec()` / `run()` starts a fresh guest process so in-memory state never leaks between runs. See [Process Isolation](/docs/architecture).\n- **npm compatibility.** Real npm packages run unmodified inside the VM, resolved over a faithfully mounted `node_modules` like a real filesystem. See [Module Loading](/docs/features/module-loading).\n\n## When to use each\n\n### Use Secure Exec when\n\n- You are running **JavaScript or TypeScript** (AI tool calls, user scripts, plugins, evaluation loops).\n- You want **no vendor dependency** and to run on your own infrastructure.\n- You need **granular, deny-by-default permissions** over the filesystem, network, and child processes.\n- You are running **many short tasks** and want a small per-task footprint.\n\n### Use a container sandbox when\n\n- You need a **full OS environment**: system packages, arbitrary binaries, or languages beyond a Node-compatible runtime.\n- You need a **persistent, long-lived** environment such as a multi-hour dev session.\n- The workload genuinely needs a real kernel and a real disk.\n\n\u003CAside type=\"note\">\n**Need a full sandboxed operating system?**\n\nIf your workload needs complete sandbox environments (for example, running coding agents like Claude Code, Codex, or Amp), the [Sandbox Agent SDK](https://sandboxagent.dev/) provides a unified interface for driving agents inside sandboxes.\n\u003C/Aside>\n\n## A minimal example\n\nBooting a Secure Exec runtime takes no infrastructure beyond the installed package. The runtime owns its VM until you dispose it:\n\n```ts\nimport { NodeRuntime } from \"secure-exec\";\n\n// Network is denied by default; the guest runs in its own virtualized VM.\nconst rt = await NodeRuntime.create();\ntry {\n const result = await rt.run\u003Cnumber>(`\n __return(40 + 2);\n `);\n console.log(result.value); // 42\n} finally {\n await rt.dispose();\n}\n```\n\nThere is no container to build, no image to pull, and no daemon to keep running.\n\n## Performance\n\nBecause there is no container image or microVM to boot, a Secure Exec runtime starts in a fraction of the time a container takes, and the dominant cost is bringing up the guest runtime rather than provisioning infrastructure. For workloads that run the same kind of snippet repeatedly, reusing a live guest process drives warm execution into the low-millisecond range. See [Benchmarks](/docs/benchmarks) for measured cold-start, warm, and reuse numbers and the methodology behind them.","src/content/docs/docs/comparison/sandbox.mdx","30c73f1d1a284057","docs/features/bindings",{"id":134,"data":136,"body":142,"filePath":143,"digest":144,"deferredRender":16},{"title":137,"description":138,"editUrl":16,"head":139,"template":18,"sidebar":140,"pagefind":16,"draft":20},"Bindings","Give sandboxed guest code a narrow, curated set of host-backed capabilities.",[],{"hidden":20,"attrs":141},{},"Bindings are host-side functions the guest invokes by name:\n\n- **Where the handler runs**: on the **host**, never inside the guest sandbox.\n- **Return value**: round-trips back to the guest as JSON.\n- **Why use them**: hand untrusted guest code a narrow, curated capability surface (the kind an AI agent calls as tools) without granting it the underlying access.\n\n## Registering tools at boot\n\nPass `tools` to `NodeRuntime.create()`. Each key becomes a named command the guest can run.\n\n```ts\nimport { NodeRuntime } from \"secure-exec\";\n\nconst rt = await NodeRuntime.create({\n tools: {\n \"get-weather\": {\n description: \"Look up the current temperature for a city\",\n inputSchema: {\n type: \"object\",\n properties: { city: { type: \"string\" } },\n required: [\"city\"],\n },\n // Runs on the HOST. The return value is delivered back to the guest.\n handler: ({ city }: { city: string }) => {\n const table: Record\u003Cstring, { temp_f: number }> = {\n \"San Francisco\": { temp_f: 61 },\n Tokyo: { temp_f: 75 },\n };\n return table[city] ?? { temp_f: null };\n },\n },\n },\n});\n```\n\n*[See Full Example](https://github.com/rivet-dev/secure-exec/tree/main/examples/docs/uc-code-mode)*\n\n## Registering tools on a live runtime\n\nYou can also add tools after the VM is running with `rt.registerTools({...})`. This is the same capability as the `tools` create option, exposed for a running runtime.\n\n```ts\nawait rt.registerTools({\n reverse: {\n description: \"Reverse a string\",\n inputSchema: {\n type: \"object\",\n properties: { text: { type: \"string\" } },\n required: [\"text\"],\n },\n handler: ({ text }: { text: string }) => ({ result: [...text].reverse().join(\"\") }),\n },\n});\n```\n\nWhen you register tools on a live runtime, make sure the `tool` permission scope is granted (see below) so the tools are invocable.\n\n## The tool definition\n\nA `HostToolDefinition` has these fields:\n\n- **`description`** (required): human-readable summary of what the tool does.\n- **`inputSchema`** (required): JSON Schema describing the input.\n- **`handler(input)`** (required): the function that runs on the host, returning a JSON-serializable value.\n- **`timeoutMs`** (optional): abort the host handler after this many milliseconds.\n- **`examples`** (optional): worked examples (each `{ description, input }`) shown alongside the tool.\n- **`commandAliases`** (optional): extra command names the guest may use, beyond the registered key.\n\n```ts\nconst rt = await NodeRuntime.create({\n tools: {\n lookupWeather: {\n description: \"Look up the current weather for a city\",\n inputSchema: {\n type: \"object\",\n properties: { city: { type: \"string\" } },\n required: [\"city\"],\n },\n timeoutMs: 5000,\n examples: [{ description: \"Weather in Tokyo\", input: { city: \"Tokyo\" } }],\n commandAliases: [\"weather\"],\n handler: async ({ city }: { city: string }) => {\n // Real host access lives here, behind the tool boundary. The guest\n // never gets the network credential, only the curated result.\n const res = await fetch(`https://example.com/weather?city=${city}`);\n return await res.json();\n },\n },\n },\n});\n```\n\nThe full type shape is in the [TypeScript SDK reference](/docs/sdks/typescript).\n\n## Invoking a tool from the guest\n\nGuest code calls a tool with the `callHostTool(name, input)` global. It returns a promise that resolves with the host handler's JSON result:\n\n```ts\nawait rt.exec(`\n const { temp_f } = await callHostTool(\"get-weather\", { city: \"Tokyo\" });\n console.log(temp_f); // 75\n`);\n```\n\n`callHostTool` is available in every guest program run through `exec`, `run`, and `spawn`. A `commandAlias` (for example `weather` above) works in place of the registered key.\n\nUnder the hood, a registered tool is exposed two ways:\n\n- **As a `PATH` command**: resolved as `/usr/bin/\u003Cname>` inside the VM, so the same invocation can be driven directly through `node:child_process` if you prefer.\n- **Via `callHostTool`**: a thin wrapper over exactly that command path, so both share the same permission and validation behavior.\n\n```ts\nawait rt.exec(`\n import { execFileSync } from \"node:child_process\";\n\n const input = { city: \"Tokyo\" };\n // argv[0] is the command name, then --json and the JSON-encoded input.\n const out = execFileSync(\"get-weather\", [\"get-weather\", \"--json\", JSON.stringify(input)]);\n // The raw command writes a { ok, result } envelope; the handler's return\n // value is under \"result\". callHostTool unwraps this for you.\n const { ok, result } = JSON.parse(out.toString());\n console.log(result.temp_f); // 75\n`);\n```\n\n## The `tool` permission scope\n\nTool invocation is gated by the `tool` permission scope.\n\n- When you pass `tools` to `create()` and set **no** `tool` policy, the `tool` scope is auto-granted so your tools are invocable out of the box.\n- Otherwise grant it explicitly so tools can run:\n\n```ts\nconst rt = await NodeRuntime.create({\n tools: { /* ... */ },\n permissions: { tool: \"allow\" },\n});\n```\n\nUse a rule set instead of `\"allow\"` for per-tool gating, allowing some tool names while denying others. See [Permissions](/docs/features/permissions) for rule-set semantics.\n\n## Wiring a tool into an LLM agent\n\nBindings pair naturally with an LLM agent: expose a sandbox capability to the model as a tool and let the model drive it through its own tool-calling loop.\n\nThe example below uses the Vercel AI SDK to give the model a `runJs` tool whose `execute` runs guest code inside the runtime. The model-generated code is untrusted input, but it executes only inside the VM under the secure-default policy (network denied here), so the model can experiment freely without reaching the host.\n\n```ts\nimport { NodeRuntime } from \"secure-exec\";\nimport { generateText, tool } from \"ai\";\nimport { openai } from \"@ai-sdk/openai\";\nimport { z } from \"zod\";\n\nconst rt = await NodeRuntime.create({ permissions: { network: \"deny\" } });\n\nawait generateText({\n model: openai(\"gpt-4o\"),\n prompt: \"Compute the 10th Fibonacci number by writing JavaScript.\",\n tools: {\n runJs: tool({\n description: \"Run JavaScript inside the sandbox and capture its output.\",\n inputSchema: z.object({ code: z.string() }),\n execute: async ({ code }) => {\n const result = await rt.exec(code);\n return { stdout: result.stdout, stderr: result.stderr };\n },\n }),\n },\n});\n```","src/content/docs/docs/features/bindings.mdx","88313ae73ad96967","docs/features/child-processes",{"id":145,"data":147,"body":153,"filePath":154,"digest":155,"deferredRender":16},{"title":148,"description":149,"editUrl":16,"head":150,"template":18,"sidebar":151,"pagefind":16,"draft":20},"Child Processes","Spawn child processes from sandboxed code.",[],{"hidden":20,"attrs":152},{},"import { Aside, LinkCard } from '@astrojs/starlight/components';\n\nTwo ways to run processes in Secure Exec:\n\n- **Guest `node:child_process`**: guest code spawns commands inside the VM. Every child is a kernel-managed process, never a real host process.\n- **`rt.spawn(code)`**: the host starts a long-running guest program and gets a live handle (`pid`, `writeStdin`, `kill`, `wait`, `exitCode`).\n\n## Guest child_process\n\nGuest code uses the standard `node:child_process` module to spawn commands available in the VM (`sh`, `node`, and the mounted coreutils):\n\n```ts\nimport { NodeRuntime } from \"secure-exec\";\n\nconst rt = await NodeRuntime.create();\n\ntry {\n const { stdout, stderr, exitCode } = await rt.exec(`\n import { execFileSync } from \"node:child_process\";\n\n // Spawn a shell command and capture its stdout.\n const shellOut = execFileSync(\"sh\", [\"-c\", \"echo hello from a child process\"], {\n encoding: \"utf8\",\n });\n console.log(\"sh output:\", shellOut.trim());\n\n // Spawn node as a child process and read its version.\n const nodeVersion = execFileSync(\"node\", [\"--version\"], {\n encoding: \"utf8\",\n });\n console.log(\"child node version:\", nodeVersion.trim());\n `);\n\n console.log(\"exitCode:\", exitCode);\n if (stderr.trim()) console.log(\"guest stderr:\", stderr.trim());\n console.log(\"guest stdout:\");\n console.log(stdout.trim());\n} finally {\n await rt.dispose();\n}\n```\n\n*[See Full Example](https://github.com/rivet-dev/secure-exec/tree/main/examples/docs/feat-child-processes)*\n\nOutput:\n\n```\nexitCode: 0\nguest stdout:\nsh output: hello from a child process\nchild node version: v22.0.0\n```\n\n- `execFileSync` is used for brevity; the async/streaming APIs (`spawn`, `exec`, `execFile`) also work for incremental stdout/stderr or writing to a child's stdin.\n- Children run any command provided by the mounted runtimes. By default that is WASM-backed `sh` + coreutils and V8-backed `node`.\n- Point at a different set of WASM command binaries with `commandsDir`:\n\n```ts\nconst rt = await NodeRuntime.create({\n commandsDir: \"/path/to/wasm/commands\",\n});\n```\n\n\u003CAside type=\"note\">Child processes always run inside the kernel. Guest code cannot reach a real host process or host binary; `node:child_process` only sees the commands the VM mounts.\u003C/Aside>\n\n### Where the commands come from\n\nThe guest `sh` and the coreutils it drives ship as WASM binaries. The kernel cannot spawn any guest process without them, so they are mounted through the WASM runtime at boot. This is how `node:child_process` and the shell work inside the VM with no host processes ever involved.\n\nThe `commandsDir` create option overrides where those WASM command binaries are loaded from. When unset, the runtime resolves a directory using the first match in this order:\n\n1. an explicit `commandsDir` option,\n2. the `SECURE_EXEC_WASM_COMMANDS_DIR` environment variable,\n3. the in-repo build output (`registry/native/target/wasm32-wasip1/release/commands`), present only in developer checkouts,\n4. the commands vendored into the installed `@secure-exec/core` package (published installs).\n\nThe in-repo build output wins over the bundled copy so local edits are picked up without re-vendoring; a fresh `npm install` has no in-repo path and falls through to the vendored commands. See the [TypeScript SDK reference](/docs/sdks/typescript) for the full create-option shape.\n\n## Long-running guests with rt.spawn\n\n`rt.exec` runs to completion and returns captured output. `rt.spawn(code)` returns a live handle immediately while the guest keeps running. It is the building block for dev servers and other long-lived guests.\n\n```ts\nconst proc = await rt.spawn(`\n process.stdin.on(\"data\", (chunk) => {\n process.stdout.write(\"got: \" + chunk.toString());\n });\n`);\n\nproc.writeStdin(\"hello\\n\"); // feed stdin\nproc.closeStdin(); // signal end-of-input\n\nconst exitCode = await proc.wait();\nconsole.log(proc.pid, exitCode);\n```\n\nSee the [TypeScript SDK reference](/docs/sdks/typescript) for the full `NodeRuntimeProcess` and `NodeRuntimeSpawnOptions` shapes. Stream output by passing `onStdout` / `onStderr`, which receive raw `Uint8Array` chunks:\n\n```ts\nconst proc = await rt.spawn(\"setInterval(() => console.log('tick'), 100)\", {\n onStdout: (chunk) => process.stdout.write(new TextDecoder().decode(chunk)),\n});\n// ... later\nproc.kill(); // SIGTERM\nawait proc.wait();\n```\n\n### Driving a guest server\n\nSpawn a server, wait for it to listen, then drive requests into it with `rt.fetch`, entirely inside the VM, even when guest network egress is denied:\n\n```ts\nconst server = await rt.spawn(`\n import http from \"node:http\";\n http.createServer((_, res) => res.end(\"ok\")).listen(3000);\n`);\n\nconst listener = await rt.waitForListener({ port: 3000 });\nconst res = await rt.fetch(listener.port ?? 3000, { path: \"/\" });\nconsole.log(res.status, res.body); // 200 ok\n\nserver.kill();\nawait server.wait();\n```\n\n## Underlying process model\n\n- The kernel process table, signals, and shell that back `node:child_process` and `rt.spawn` are documented in agentOS: [Processes & Shell](https://agentos-sdk.dev/docs/processes).","src/content/docs/docs/features/child-processes.mdx","f5b1b2345a794ae8","docs/features/executing-code",{"id":156,"data":158,"body":164,"filePath":165,"digest":166,"deferredRender":16},{"title":159,"description":160,"editUrl":16,"head":161,"template":18,"sidebar":162,"pagefind":16,"draft":20},"Executing Code","Run guest JavaScript with exec() and run(), and return values from the sandbox.",[],{"hidden":20,"attrs":163},{},"import { LinkCard } from '@astrojs/starlight/components';\n\n`exec()` and `run()` are the two ways to run guest code to completion. The code\nruns inside the VM as a standard ES module, so top-level `import` and top-level\n`await` both work.\n\n## Run code and capture output\n\n`exec()` runs the code and resolves with `stdout`, `stderr`, and `exitCode`.\n\n```ts\nimport { NodeRuntime } from \"secure-exec\";\n\nconst rt = await NodeRuntime.create();\nconst { stdout, exitCode } = await rt.exec(`\n import os from \"node:os\";\n console.log(\"platform:\", os.platform());\n`);\nconsole.log(stdout, exitCode);\nawait rt.dispose();\n```\n\n## Return a value from the guest\n\n`run\u003CT>()` does everything `exec()` does and also decodes a JSON-serializable\nvalue the guest hands back with the injected `globalThis.__return(value)`. If the\nguest never calls it, `value` is `undefined`.\n\n```ts\nconst { value } = await rt.run\u003C{ sum: number }>(`\n globalThis.__return({ sum: 2 + 40 });\n`);\nconsole.log(value?.sum); // 42\n```\n\n## Per-run options\n\n`exec()` and `run()` take the same per-call options: `stdin` to pipe input, `env`\nand `cwd` to override the environment for one run, a `timeout` and an\n`AbortSignal` to bound it, and `onStdout` / `onStderr` to stream output as it is\nproduced.\n\n```ts\nconst result = await rt.run\u003Cstring>(\n `\n let input = \"\";\n for await (const chunk of process.stdin) input += chunk;\n globalThis.__return(input.trim().toUpperCase());\n `,\n { stdin: \"piped through stdin\", timeout: 10_000 },\n);\n```\n\nGuest code can also invoke host-side tools you register with the `tools` option\non `NodeRuntime.create()`: each becomes a named command the guest runs by name,\nround-tripping its JSON input to a handler on the host. For the full option and\nresult shapes, see the [TypeScript SDK reference](/docs/sdks/typescript).\n\n*[See Full Example](https://github.com/rivet-dev/secure-exec/tree/main/examples/docs/sdk-overview)*\n\n## Related\n\n\u003CLinkCard title=\"Output Capture\" href=\"/docs/features/output-capture\" description=\"The result shape and streaming stdout/stderr as it is produced.\" />\n\u003CLinkCard title=\"Resident Runner\" href=\"/docs/features/resident-runner\" description=\"Reuse a live guest process for low-latency repeated execution.\" />\n\u003CLinkCard title=\"Child Processes\" href=\"/docs/features/child-processes\" description=\"spawn() long-running guests and the guest child_process surface.\" />\n\u003CLinkCard title=\"Resource Limits\" href=\"/docs/features/resource-limits\" description=\"Bound a run with timeout, AbortSignal, and the VM's limits.\" />\n\u003CLinkCard title=\"Bindings\" href=\"/docs/features/bindings\" description=\"Register host-side tools the guest invokes by name.\" />","src/content/docs/docs/features/executing-code.mdx","96cc9f61fe1f7fed","docs/features/filesystem",{"id":167,"data":169,"body":175,"filePath":176,"digest":177,"deferredRender":16},{"title":170,"description":171,"editUrl":16,"head":172,"template":18,"sidebar":173,"pagefind":16,"draft":20},"Filesystem","A short overview of the Secure Exec filesystem, with a link to the canonical agentOS filesystem docs.",[],{"hidden":20,"attrs":174},{},"import { LinkCard } from '@astrojs/starlight/components';\n\nEach VM presents a normal POSIX filesystem to guest code, backed by a virtual filesystem inside the kernel. At a glance:\n\n- **Per-VM virtual filesystem**: Every VM gets its own isolated virtual filesystem. One VM cannot see or reach another VM's files.\n- **Never touches the host disk**: Guest filesystem calls are served entirely inside the kernel and never read or write the real host disk.\n- **Normal POSIX and Node APIs**: The standard `node:fs` and `node:fs/promises` APIs work as usual against the virtual filesystem, so ordinary programs run unchanged.\n- **Mountable backends**: You can project host-backed sources into the guest filesystem, Docker-style, including host directories and S3. Mounts are confined to their root, and the guest sees only the mounted subtree.\n\n## Full reference\n\nThe canonical filesystem API, including seeding files, host-boundary file exchange, and the full mount and backend configuration, is owned by agentOS.\n\n\u003CLinkCard\n title=\"agentOS: Filesystem\"\n href=\"https://agentos-sdk.dev/docs/filesystem\"\n description=\"The complete filesystem API plus mount and backend configuration details.\"\n/>","src/content/docs/docs/features/filesystem.mdx","fa69a9916a61aa9a","docs/features/module-loading",{"id":178,"data":180,"body":186,"filePath":187,"digest":188,"deferredRender":16},{"title":181,"description":182,"editUrl":16,"head":183,"template":18,"sidebar":184,"pagefind":16,"draft":20},"NPM & Module Loading","How sandboxed code resolves and loads modules.",[],{"hidden":20,"attrs":185},{},"import { Aside } from '@astrojs/starlight/components';\n\nGuest `import` and `require` resolve against the VM's virtual filesystem, never the host module loader. Resolution runs entirely inside the kernel. By default the guest sees an empty `node_modules`; project host packages into the VM with `nodeModules` (or `mounts`) to run real npm packages (including the TypeScript compiler) in-sandbox.\n\n## Loading Modules\n\n- Guest source runs as a standard ES module: `import`, `import.meta.url`, and top-level `await` all work.\n- Build a CommonJS `require` with `createRequire(import.meta.url)`.\n- Both paths resolve through the kernel's module loader.\n\n```ts\nimport { NodeRuntime } from \"secure-exec\";\n\nconst rt = await NodeRuntime.create();\n\ntry {\n const { stdout, stderr, exitCode } = await rt.exec(`\n // ESM import of a Node builtin.\n import { basename, join } from \"node:path\";\n\n // CommonJS require, created from the current module URL.\n import { createRequire } from \"node:module\";\n const require = createRequire(import.meta.url);\n const os = require(\"node:os\");\n\n const resolved = {\n basename: basename(\"/workspace/data/report.txt\"),\n joined: join(\"/workspace\", \"data\", \"report.txt\"),\n platform: os.platform(),\n };\n\n console.log(\"resolved node:path via import ->\", resolved.joined);\n console.log(\"resolved node:os via require ->\", resolved.platform);\n console.log(JSON.stringify(resolved));\n `);\n\n console.log(\"exitCode:\", exitCode);\n if (stderr.trim()) console.log(\"guest stderr:\\n\" + stderr.trim());\n console.log(\"guest stdout:\");\n console.log(stdout.trim());\n} finally {\n await rt.dispose();\n}\n```\n\n*[See Full Example](https://github.com/rivet-dev/secure-exec/tree/main/examples/docs/feat-module-loading)*\n\n```\nexitCode: 0\nguest stdout:\nresolved node:path via import -> /workspace/data/report.txt\nresolved node:os via require -> linux\n{\"basename\":\"report.txt\",\"joined\":\"/workspace/data/report.txt\",\"platform\":\"linux\"}\n```\n\n\u003CAside type=\"note\">Resolution runs inside the kernel against the guest's virtual filesystem. The guest only sees what is present there; mounting host `node_modules` (below) makes those packages part of that filesystem so they resolve like any other guest module.\u003C/Aside>\n\n## Loading real npm packages\n\nPut package bytes on the guest filesystem, then let the in-kernel resolver walk them. Three ways to project them:\n\n- `create({ nodeModules })`: project a whole host `node_modules` tree in one call. Read-only, defaulting to `/tmp/node_modules`, which is where the resolution walk begins for a program run by `exec()` / `run()` (each program is written under `/tmp`). Pass the object form (`{ hostPath, guestPath }`) to mount it elsewhere.\n- `create({ mounts })`: project one host directory at a time onto a guest path, Docker-style. Use a `mounts` entry per package when you want fine-grained control instead of the whole tree.\n- `create({ files })` or `rt.writeFile`: write bytes directly into the VM when you want to seed files instead of projecting a host tree.\n\nEither way the host filesystem is never exposed; the guest sees only the projected subtree or the bytes you write. For the full mount shapes see [the TypeScript SDK reference](/docs/sdks/typescript).\n\nThe example below points `nodeModules` at the host directory that holds `is-number`, then imports it from inside the VM. The guest resolves it the way Node would over a real filesystem, including through `createRequire`.\n\n```ts\nimport { fileURLToPath } from \"node:url\";\nimport { NodeRuntime } from \"secure-exec\";\n\nconst hostNodeModules = fileURLToPath(\n new URL(\"../../../../node_modules\", import.meta.url),\n);\n\nconst mounted = await NodeRuntime.create({\n nodeModules: hostNodeModules,\n});\n\ntry {\n const { stdout, stderr, exitCode } = await mounted.exec(`\n // ESM import of the real, host-mounted npm package.\n import isNumber from \"is-number\";\n\n // The same package also resolves through a CommonJS require.\n import { createRequire } from \"node:module\";\n const require = createRequire(import.meta.url);\n const isNumberCjs = require(\"is-number\");\n\n const result = {\n \"isNumber(42)\": isNumber(42),\n 'isNumber(\"3.14\")': isNumber(\"3.14\"),\n 'isNumber(\"nope\")': isNumber(\"nope\"),\n sameModule: isNumber === isNumberCjs,\n };\n\n console.log(\"loaded real npm package is-number\");\n console.log(JSON.stringify(result));\n `);\n\n console.log(\"exitCode:\", exitCode);\n if (stderr.trim()) console.log(\"guest stderr:\\n\" + stderr.trim());\n console.log(\"guest stdout:\");\n console.log(stdout.trim());\n} finally {\n await mounted.dispose();\n}\n```\n\n*[See Full Example](https://github.com/rivet-dev/secure-exec/tree/main/examples/docs/feat-module-loading)*\n\n```\nexitCode: 0\nguest stdout:\nloaded real npm package is-number\n{\"isNumber(42)\":true,\"isNumber(\\\"3.14\\\")\":true,\"isNumber(\\\"nope\\\")\":false,\"sameModule\":true}\n```\n\n## node_modules resolution\n\nWhen a guest filesystem contains `node_modules`, the resolver matches naive Node.js resolution over it, Docker-style:\n\n- ancestor `node_modules` walk from the importing module up to the root,\n- `package.json` `exports`/`imports` and conditions,\n- `realpath`/symlink following.\n\nNo package-manager-specific heuristics: pnpm/yarn layouts resolve because the VFS exposes their symlinks, not because the resolver special-cases them.\n\n## Seeding files directly\n\nWhen you don't have a host directory to mount, write bytes into the VM:\n\n```ts\n// At boot.\nconst rt = await NodeRuntime.create({\n files: { \"/tmp/node_modules/greet/index.js\": \"module.exports = () => 'hi';\" },\n});\n\n// Or after boot.\nawait rt.writeFile(\"/tmp/node_modules/greet/package.json\", '{\"main\":\"index.js\"}');\nconst bytes = await rt.readFile(\"/tmp/node_modules/greet/index.js\");\n```","src/content/docs/docs/features/module-loading.mdx","b5b27e6743674da6","docs/features/networking",{"id":189,"data":191,"body":197,"filePath":198,"digest":199,"deferredRender":16},{"title":192,"description":193,"editUrl":16,"head":194,"template":18,"sidebar":195,"pagefind":16,"draft":20},"Networking","A short overview of Secure Exec networking, with a link to the canonical agentOS networking docs.",[],{"hidden":20,"attrs":196},{},"import { LinkCard } from '@astrojs/starlight/components';\n\nSecure Exec virtualizes all VM networking so guest code never touches the real host network. At a glance:\n\n- **One kernel socket table**: Guest `fetch()`, `node:http`, and raw sockets all flow through the kernel socket table, never the real host network.\n- **Loopback-only by default**: A guest can bind and reach loopback services inside its own VM, but the socket table stays hermetic and cannot reach a real host loopback service.\n- **Allowlist-gated egress**: Outbound networking is denied by default and opted into via the `network` permission, either allowing everything or scoping to specific patterns.\n- **Proxied host-to-guest**: Host loopback ports are not visible to the guest unless explicitly exposed through `loopbackExemptPorts`.\n\n## Full reference\n\nThe canonical networking API, permission rules, and egress details are owned by agentOS.\n\n\u003CLinkCard\n title=\"agentOS: Networking\"\n href=\"https://agentos-sdk.dev/docs/networking\"\n description=\"The complete networking API, permission rules, and egress configuration.\"\n/>","src/content/docs/docs/features/networking.mdx","17675a4280793b22","docs/features/output-capture",{"id":200,"data":202,"body":208,"filePath":209,"digest":210,"deferredRender":16},{"title":203,"description":204,"editUrl":16,"head":205,"template":18,"sidebar":206,"pagefind":16,"draft":20},"Output Capture","Capture console output from sandboxed code.",[],{"hidden":20,"attrs":207},{},"`exec()` runs guest code and resolves with its captured output once the guest process exits.\n\n- `stdout` and `stderr` are buffered as separate strings, so output on one channel never bleeds into the other.\n- `exitCode` is the guest process's exit status.\n- Buffering into strings bounds host memory: each channel is held as one string, not an unbounded backlog of live chunks.\n\n## Capturing output\n\n```ts\nimport { NodeRuntime } from \"secure-exec\";\n\nconst rt = await NodeRuntime.create();\n\ntry {\n\tconst { stdout, stderr, exitCode } = await rt.exec(`\n\t\tconsole.log(\"hello from the sandbox\");\n\t\tconsole.error(\"oops from the sandbox\");\n\t\tprocess.exit(3);\n\t`);\n\n\tconsole.log(\"exitCode:\", exitCode);\n\tconsole.log(\"stdout:\", JSON.stringify(stdout));\n\tconsole.log(\"stderr:\", JSON.stringify(stderr));\n} finally {\n\tawait rt.dispose();\n}\n```\n\n*[See Full Example](https://github.com/rivet-dev/secure-exec/tree/main/examples/docs/feat-output-capture)*\n\nPrints:\n\n```\nexitCode: 3\nstdout: \"hello from the sandbox\\n\"\nstderr: \"oops from the sandbox\\n\"\n```\n\n`process.exit(3)` is why `exitCode` is `3`.\n\n`run()` adds one more field. It resolves to the same `stdout`, `stderr`, and `exitCode`, plus a decoded `value` the guest hands back by calling `globalThis.__return(value)`:\n\n```ts\nconst { value, exitCode } = await rt.run(`\n\tconst sum = [1, 2, 3].reduce((a, b) => a + b, 0);\n\tglobalThis.__return({ sum });\n`);\n\nconsole.log(exitCode, value); // 0 { sum: 6 }\n```\n\n`value` is the JSON-decoded argument passed to `__return()`. It is only populated when `exitCode === 0` and the guest actually called `__return()`; otherwise it is `undefined`, while `stdout`, `stderr`, and `exitCode` are still captured.\n\nSee [the TypeScript SDK reference](/docs/sdks/typescript) for the full result and option shapes.\n\n## Streaming output\n\nPass `onStdout` / `onStderr` to observe output incrementally as it is produced. The full strings are still returned when the run ends.\n\n- Each callback receives a `Uint8Array` chunk. Decode text with a `TextDecoder`.\n- Available on both `exec()` and `run()`, and on `spawn()` via `NodeRuntimeSpawnOptions`.\n\n```ts\nconst decoder = new TextDecoder();\n\nconst { stdout, exitCode } = await rt.exec(\n\t`\n\t\tfor (let i = 0; i \u003C 3; i++) console.log(\"tick\", i);\n\t`,\n\t{\n\t\tonStdout: (chunk) => process.stdout.write(decoder.decode(chunk)),\n\t\tonStderr: (chunk) => process.stderr.write(decoder.decode(chunk)),\n\t},\n);\n// stdout still holds the complete buffered output after the run.\n```\n\n## Feeding input and cancelling\n\n`exec()`, `run()`, and `spawn()` take the same options object. Beyond the streaming hooks above, the common ones are `stdin` to pipe input in, `signal` to cancel, plus `env`, `cwd`, and `timeout`. The [TypeScript SDK reference](/docs/sdks/typescript) lists them all.\n\nFeed input and read everything back as buffered strings:\n\n```ts\nconst { stdout } = await rt.exec(\n\t`process.stdin.pipe(process.stdout);`,\n\t{ stdin: \"echo me back\\n\" },\n);\n// stdout === \"echo me back\\n\"\n```\n\nCancel an in-flight run with `signal`; the guest process is killed inside the VM and the call rejects with the abort reason:\n\n```ts\nconst controller = new AbortController();\nconst pending = rt.exec(\"while (true) {}\", { signal: controller.signal });\ncontroller.abort();\nawait pending.catch((err) => console.log(err.name)); // \"AbortError\"\n```\n\n## Common patterns\n\nUse `exitCode` to detect failure, with `stderr` for the diagnostic:\n\n```ts\nconst { stderr, exitCode } = await rt.exec(code);\nif (exitCode !== 0) throw new Error(`guest exited ${exitCode}: ${stderr}`);\n```\n\nFor long-running guests that never exit (dev servers), use `spawn()` instead: it returns a live `NodeRuntimeProcess` handle with the same `onStdout`/`onStderr` streaming, plus `writeStdin`, `kill`, and `wait()`.","src/content/docs/docs/features/output-capture.mdx","d51a9fad499a4a32","docs/features/permissions",{"id":211,"data":213,"body":219,"filePath":220,"digest":221,"deferredRender":16},{"title":214,"description":215,"editUrl":16,"head":216,"template":18,"sidebar":217,"pagefind":16,"draft":20},"Permissions","A short overview of Secure Exec permissions, with a link to the canonical agentOS permissions docs.",[],{"hidden":20,"attrs":218},{},"import { LinkCard } from '@astrojs/starlight/components';\n\nSecure Exec checks a per-domain permission policy against every guest syscall, so denied operations are rejected before any host resource is touched. At a glance:\n\n- **Per-domain policy**: Each domain (`fs`, `network`, `childProcess`, `process`, `env`, `tool`) is configured independently against every guest syscall.\n- **Allow, deny, or rules**: A domain takes a mode (`\"allow\"` or `\"deny\"`) or a rule set (`{ default, rules }`) for fine-grained control.\n- **Enforced before the host**: A denied operation is rejected with `EACCES` before any host resource (socket, file) is opened.\n- **Secure defaults**: The network is deny-by-default; filesystem, child processes, process info, and env are enabled so normal programs run.\n- **Trusted policy, untrusted subject**: The policy is set by the host, but the guest is the subject it binds. A denied domain holds even when guest code actively tries to escape it.\n\n## Full reference\n\nThe complete permission scopes, modes, and rule configuration are owned by agentOS.\n\n\u003CLinkCard\n title=\"agentOS: Permissions\"\n href=\"https://agentos-sdk.dev/docs/permissions\"\n description=\"The complete permission scopes, modes, and rule configuration.\"\n/>","src/content/docs/docs/features/permissions.mdx","cc4a23bc3327a6e3","docs/features/resident-runner",{"id":222,"data":224,"body":230,"filePath":231,"digest":232,"deferredRender":16},{"title":225,"description":226,"editUrl":16,"head":227,"template":18,"sidebar":228,"pagefind":16,"draft":20},"Resident Runner","Reuse a live guest process for low-latency repeated execution.",[],{"hidden":20,"attrs":229},{},"import { Aside, LinkCard } from '@astrojs/starlight/components';\n\nEach `exec()` / `run()` call starts a fresh guest process, which is the right\ndefault for isolation between runs. When you run many small snippets against the\nsame runtime (an evaluation loop, a REPL, a test harness), that per-run process\nstartup dominates. A resident runner keeps one guest process alive and evaluates\neach snippet in it, so repeated calls are fast.\n\n\u003CAside type=\"note\">\nA resident runner trades per-run process isolation for speed: snippets share the\nsame process, so in-memory state can carry between calls. Use it for trusted,\nrepeated evaluation. For isolation between runs, use `exec()` / `run()`.\n\u003C/Aside>\n\n## Creating and using a runner\n\n`createResidentRunner()` returns a handle with `exec()` and `dispose()`. Dispose\nit when you are done so the live process is torn down.\n\n```ts\nimport { NodeRuntime } from \"secure-exec\";\n\nconst rt = await NodeRuntime.create();\nconst runner = await rt.createResidentRunner();\ntry {\n const a = await runner.exec(\"console.log(1 + 1)\");\n const b = await runner.exec(\"console.log(2 + 2)\");\n console.log(a.stdout.trim(), b.stdout.trim()); // \"2\" \"4\"\n} finally {\n await runner.dispose();\n await rt.dispose();\n}\n```\n\nEach `runner.exec(code, options?)` resolves with the same\n`{ stdout, stderr, exitCode }` shape as `rt.exec()`. Pass `options.timeout` to\nbound a single evaluation.\n\n## When to use it\n\nA warm resident evaluation runs in roughly a millisecond, versus the hundreds of\nmilliseconds a cold run pays to stand up a guest process. Reach for a resident\nrunner when the same runtime runs many small snippets and the snippets are\ntrusted to share a process. See the measured difference in\n[Benchmarks](/docs/benchmarks).\n\n\u003CLinkCard title=\"TypeScript SDK reference\" href=\"/docs/sdks/typescript\" description=\"createResidentRunner() and the NodeRuntimeResidentRunner handle.\" />","src/content/docs/docs/features/resident-runner.mdx","461cf8e9e3bac06e","docs/features/resource-limits",{"id":233,"data":235,"body":241,"filePath":242,"digest":243,"deferredRender":16},{"title":236,"description":237,"editUrl":16,"head":238,"template":18,"sidebar":239,"pagefind":16,"draft":20},"Resource Limits","A short overview of Secure Exec resource limits, with a link to the canonical agentOS resource limits docs.",[],{"hidden":20,"attrs":240},{},"import { LinkCard } from '@astrojs/starlight/components';\n\nSecure Exec bounds each VM with per-VM resource caps so untrusted guest code can never exhaust the host. At a glance:\n\n- **Per-VM caps**: Each VM gets its own ceilings on concurrent processes, open file descriptors, sockets, total filesystem bytes, and WASM stack depth.\n- **Kernel-enforced**: The kernel mediates and accounts for every allocation. There is no path for the guest to reach host resources around these limits.\n- **Guest-local failure**: A guest that exceeds a cap fails inside its own VM with a normal POSIX errno, exactly as it would on real Linux.\n- **Host is unaffected**: Hitting a limit terminates or fails the guest operation only; the sidecar and host process stay intact and the VM keeps running.\n- **Operator-raisable**: The caller configures the limits per VM and can raise or lower them to fit the workload.\n\n## Full reference\n\nThe canonical limit names, defaults, and configuration API are owned by agentOS.\n\n\u003CLinkCard\n title=\"agentOS: Resource Limits\"\n href=\"https://agentos-sdk.dev/docs/resource-limits\"\n description=\"The complete set of per-VM resource limits, defaults, and configuration options.\"\n/>","src/content/docs/docs/features/resource-limits.mdx","59142e295682caec","docs/features/runtime-platform",{"id":244,"data":246,"body":252,"filePath":253,"digest":254,"deferredRender":16},{"title":247,"description":248,"editUrl":16,"head":249,"template":18,"sidebar":250,"pagefind":16,"draft":20},"Runtime & Platform","Customize the host environment guest code sees (the full Node.js surface today), plus the platform ladder (node, browser, neutral, bare) the kernel models.",[],{"hidden":20,"attrs":251},{},"import { LinkCard } from '@astrojs/starlight/components';\n\n`NodeRuntime.create()` shapes the host environment guest code sees before it\nboots, and the kernel models that environment as a ladder of platforms (`node`,\n`browser`, `neutral`, `bare`). Guest code always runs inside a kernel-backed V8\nisolate with zero host escapes: every syscall (filesystem, network, child\nprocess) goes through the kernel, never the real host.\n\nThis page covers the customization surface: seeding and selecting the host\nenvironment, then the `moduleResolution` and `allowedBuiltins` knobs the wire\nconfig exposes. Start by probing the default `node` surface:\n\n```ts\nimport { NodeRuntime } from \"secure-exec\";\n\nconst rt = await NodeRuntime.create();\n\ntry {\n\tconst probe = await rt.run\u003C{\n\t\tplatform: string;\n\t\thasProcess: boolean;\n\t\thasBuffer: boolean;\n\t\tnodeVersion: string;\n\t\tsha256: string;\n\t\tjoinedPath: string;\n\t}>(`\n\t\tconst { createHash } = await import(\"node:crypto\");\n\t\tconst { join } = await import(\"node:path\");\n\n\t\tconst sha256 = createHash(\"sha256\").update(\"secure-exec\").digest(\"hex\");\n\n\t\tglobalThis.__return({\n\t\t\tplatform: typeof process !== \"undefined\" ? process.platform : \"(no process)\",\n\t\t\thasProcess: typeof process !== \"undefined\",\n\t\t\thasBuffer: typeof Buffer !== \"undefined\",\n\t\t\tnodeVersion: typeof process !== \"undefined\" ? process.versions.node : \"(none)\",\n\t\t\tsha256,\n\t\t\tjoinedPath: join(\"/home/agentos\", \"report.txt\"),\n\t\t});\n\t`);\n\n\tconsole.log(probe.value);\n} finally {\n\tawait rt.dispose();\n}\n```\n\n*[See Full Example](https://github.com/rivet-dev/secure-exec/tree/main/examples/docs/feat-runtime-platform)*\n\nOutput, the guest host environment as seen from inside the isolate:\n\n```text\n{\n platform: 'linux',\n hasProcess: true,\n hasBuffer: true,\n nodeVersion: '22.0.0',\n sha256: 'fa7ce60dac0cc1bfe7424a68e47ad3d712345cf936431bb147cd5f5de0371a4a',\n joinedPath: '/home/agentos/report.txt'\n}\n```\n\n:::note[Guest `run()` and `exec()` code both run as ES modules]\nBoth `rt.run()` and `rt.exec()` write your code into an `.mjs` module, so\ntop-level `import` and top-level `await` work in either. `run()` injects a\n`globalThis.__return(value)` helper you call to hand a JSON-serializable value\nback to the host (delivered as `result.value`); the example uses dynamic\n`await import(\"node:…\")` purely to keep the snippet a single expression body.\n:::\n\n## Host environment (the `node` surface)\n\nAvailable to guest code on the default platform:\n\n- **Node globals**: `process`, `Buffer`, `require`, `module`, `__dirname`, `__filename`.\n- **`node:*` builtins**: `fs`, `path`, `crypto`, `http`, `net`, `os`, `child_process`, `dns`, and the rest of the Node standard library.\n- **Node identity**: virtualized `process.versions` (Node `22.0.0`), `process.platform` (`linux`), `execPath`, and `pid`/`ppid`/`uid`/`gid`.\n- **Web platform**: `fetch`, `URL`, `TextEncoder`/`TextDecoder`, WebCrypto, `structuredClone`, `Blob`, `AbortController`.\n- **Universal primitives**: `console`, timers (`setTimeout`/`setInterval`/…), `queueMicrotask`.\n- **Language + Wasm**: the ECMAScript spec globals plus `WebAssembly`.\n\nEvery one of these is kernel-backed. `fetch` and `node:net`/`node:http` route\nthrough the kernel socket table (and are denied by default until you grant\n`network`); `node:fs` sees only the VM's virtual filesystem; `node:child_process`\nspawns kernel-managed processes.\n\n### Seeding the host environment\n\n`NodeRuntime.create()` shapes what the guest sees before and after boot:\n\n```ts\nconst rt = await NodeRuntime.create({\n\tenv: { API_BASE: \"https://example.test\" }, // guest process env\n\tcwd: \"/workspace\", // default working dir\n\tfiles: { \"/root/data.json\": '{\"ok\":true}' }, // seed VFS bytes\n\tmounts: [ // project host dirs, Docker-style, lazy\n\t\t{ guestPath: \"/root/node_modules/typescript\", hostPath: \"/abs/typescript\", readOnly: true },\n\t],\n\tpermissions: { network: \"allow\" }, // merged over secure default (network denied)\n\ttools: { // host capabilities the guest calls as commands\n\t\tadd: {\n\t\t\tdescription: \"Add two numbers\",\n\t\t\tinputSchema: { type: \"object\", properties: { a: { type: \"number\" }, b: { type: \"number\" } }, required: [\"a\", \"b\"] },\n\t\t\thandler: ({ a, b }: { a: number; b: number }) => ({ sum: a + b }),\n\t\t},\n\t},\n\tloopbackExemptPorts: [3000], // let non-loopback connections reach this port\n\tcommandsDir: \"/abs/wasm/commands\", // override the WASM `sh`/coreutils dir\n});\n```\n\n- `files` copies bytes into the VFS up front; `mounts` reads host trees lazily through the VFS, so large `node_modules` are not copied as a blob.\n- `permissions` merges over a secure default (`fs`/`childProcess`/`process`/`env` allowed, `network` denied), so `{ network: \"allow\" }` is enough to opt in.\n- `tools` auto-grants the `tool` scope when you set no `tool` policy; the guest invokes a tool by name with `--json` input over `node:child_process`.\n\nAfter boot, the same surface is reachable on the live runtime:\n\n```ts\nawait rt.writeFile(\"/root/late.json\", '{\"added\":\"after boot\"}');\nconst bytes = await rt.readFile(\"/root/late.json\"); // Uint8Array\nawait rt.registerTools({\n\tnow: { description: \"epoch ms\", inputSchema: { type: \"object\" }, handler: () => Date.now() },\n});\n```\n\n### Driving a guest dev server from the host\n\nSpawn a long-running guest, wait for it to listen, then drive an HTTP request\ninto it from the host. This works even with egress denied, because the request\nflows through the kernel socket table rather than the real host network:\n\n```ts\nconst server = await rt.spawn(`\n\timport http from \"node:http\";\n\thttp.createServer((_, res) => res.end(\"ok\")).listen(3000);\n`);\nconst listener = await rt.waitForListener({ port: 3000 });\nconst res = await rt.fetch(listener.port ?? 3000, { path: \"/\" });\nserver.kill();\nawait server.wait();\n```\n\nFor the full set of run methods (`exec`/`run`/`spawn`/`fetch`/`waitForListener`)\nand their per-run options (`env`, `cwd`, `stdin`, `timeout`, `signal`,\n`onStdout`/`onStderr`), see the TypeScript SDK reference:\n\n\u003CLinkCard\n\ttitle=\"NodeRuntime run methods and options\"\n\tdescription=\"Full signatures for exec/run/spawn/fetch/waitForListener and the shared per-run options.\"\n\thref=\"/docs/sdks/typescript\"\n/>\n\n## The platform ladder\n\nThe kernel models the guest host environment as a ladder, using esbuild's\nvocabulary (`node` / `browser` / `neutral`) plus `bare` for the language-only\ntier esbuild has no name for. `NodeRuntime` always runs the top rung (`node`);\nthe lower rungs are described here for context and are **not currently selectable\nin Secure Exec** (see the note below).\n\n| Capability | `node` | `browser` | `neutral` | `bare` |\n|---|:---:|:---:|:---:|:---:|\n| Node globals | ✅ | No | No | No |\n| `node:*` builtins | ✅ | No | No | No |\n| Node identity | ✅ | No | No | No |\n| Web platform | ✅ | ✅ | No | No |\n| Universal primitives | ✅ | ✅ | ✅ | No |\n| Language + Wasm | ✅ | ✅ | ✅ | ✅ |\n\n- **`node`** (the default): full Node.js compatibility. Nothing removed.\n- **`browser`**: a browser/Deno-like runtime. The Node surface is gone; web-standard globals remain. `crypto` is the WebCrypto object (`crypto.subtle`, `crypto.getRandomValues`), *not* the `node:crypto` module, so `crypto.randomBytes`/`crypto.createHash` are absent.\n- **`neutral`**: universal primitives only (`console`, timers, `queueMicrotask`) plus the language. No `fetch`/`URL`/WebCrypto, no Node.\n- **`bare`**: language only: the ECMAScript spec globals plus `WebAssembly`. No `console`, no timers, no `fetch`. The caller provides any host functionality the guest needs.\n\n`WebAssembly` stays available on **every tier**, including `bare`. Compilation\nhappens inside the isolate and is not a host escape.\n\n:::caution[Platform selection is not configurable in Secure Exec yet]\nThe kernel's wire protocol carries a `jsRuntime` config with `platform`,\n`moduleResolution`, and `allowedBuiltins` fields. The tiers are\nreal in the kernel, but `NodeRuntime.create()` does **not** plumb those fields\nthrough: it always boots the VM on the `node` platform with full Node module\nresolution. There is no `NodeRuntime.create()` option to select\n`browser`/`neutral`/`bare`, change module resolution, or restrict the builtin\nallow-list today. The sections below document the intended model for those fields,\nnot a `create()` option you can pass.\n:::\n\n## `moduleResolution`: how imports resolve\n\n`moduleResolution` is an independent axis of the `jsRuntime` config (any\ncombination with `platform` is valid). Set it alongside `platform` to lock down\nhow `import`/`require` specifiers resolve:\n\n```ts\nconst config: CreateVmConfig = {\n\t// …\n\tjsRuntime: {\n\t\tplatform: \"node\",\n\t\tmoduleResolution: \"relative\", // only relative/absolute paths resolve from the VFS\n\t},\n};\n```\n\nWith `moduleResolution: \"relative\"`, `import \"./util.js\"` resolves from the\nvirtual filesystem, while a bare `import \"lodash\"` or a `node:*` builtin import\nfails. The default is full Node resolution, which is what `NodeRuntime` boots:\n\n| `moduleResolution` | `import \"pkg\"` | `import \"./x.js\"` | `node:*` |\n|---|:---:|:---:|:---:|\n| `node` (default) | ✅ | ✅ | ✅ |\n| `relative` | No | ✅ | No |\n| `none` | No | No | No |\n\n(`import \"pkg\"` = bare/`node_modules` specifier; `import \"./x.js\"` = relative or\nabsolute path; `node:*` follows the platform / `allowedBuiltins`.)\n\n- **`node`**: standard Node resolution: the `node_modules` ancestor walk, `exports`/`imports`/conditions, and `realpath`/symlink following.\n- **`relative`**: only relative and absolute paths resolve from the VFS; bare package specifiers and `node:*` builtins do not.\n- **`none`**: nothing resolves. Any `import` or `require` (including relative) fails. Produces a single self-contained entrypoint module, useful for locked-down evaluation of one script.\n\n## `allowedBuiltins`: restrict Node builtins (node platform only)\n\n`allowedBuiltins` narrows which `node:*` builtin modules guest code may import.\nSet it on the `jsRuntime` config to allow exactly the builtins a script needs:\n\n```ts\nconst config: CreateVmConfig = {\n\t// …\n\tjsRuntime: {\n\t\tplatform: \"node\",\n\t\tallowedBuiltins: [\"path\", \"fs\"], // only these resolve; everything else is denied\n\t},\n};\n```\n\nWith `allowedBuiltins: [\"path\", \"fs\"]`, `import(\"node:path\")` and\n`import(\"node:fs/promises\")` succeed (a root name like `fs` also covers its\nsubpaths), while `import(\"node:child_process\")` is rejected. Omitting\n`allowedBuiltins` keeps the engine default allow-list (what `NodeRuntime` uses);\n`[]` denies all builtins. It is only valid under `platform: \"node\"`; the other\nplatforms deny all `node:*` builtins regardless, and unknown builtin names are\nrejected.\n\n\u003CLinkCard\n\ttitle=\"CreateVmConfig.jsRuntime full shape\"\n\tdescription=\"The complete jsRuntime config (platform, moduleResolution, allowedBuiltins) and the rest of CreateVmConfig.\"\n\thref=\"/docs/sdks/typescript\"\n/>","src/content/docs/docs/features/runtime-platform.mdx","81b2b41c3b3800d3","docs/features/typescript",{"id":255,"data":257,"body":263,"filePath":264,"digest":265,"deferredRender":16},{"title":258,"description":259,"editUrl":16,"head":260,"template":18,"sidebar":261,"pagefind":16,"draft":20},"TypeScript","Compiling and type-checking TypeScript inside the sandbox.",[],{"hidden":20,"attrs":262},{},"`@secure-exec/typescript` runs the TypeScript compiler **inside the sandbox**. The `typescript` package is projected into the VM's virtual filesystem and every `createProgram`/`emit` call happens in the guest, so untrusted TypeScript never compiles or runs on the host.\n\n**Why compile in the sandbox:** type-checking attacker-controlled source is a **CPU and memory amplification** vector. A small malicious type (recursive conditional types, deeply nested generics) can make `tsc` spin for seconds or balloon its heap. Because the compiler runs in a disposable VM, the blow-up is contained by the sandbox boundary, and you can bound each run with a `timeout` instead of hanging or OOM-ing the host.\n\n## Install\n\n```bash\nnpm install @secure-exec/typescript secure-exec\n```\n\n## Compile and type-check a source string\n\n```ts\nimport { createTypeScriptTools } from \"@secure-exec/typescript\";\nimport { NodeRuntime } from \"secure-exec\";\n\nconst tools = createTypeScriptTools();\n\nconst typeScriptSource = `\ninterface Greeting {\n name: string;\n count: number;\n}\n\nconst greeting: Greeting = { name: \"secure-exec\", count: 3 };\nconst lines: string[] = Array.from(\n { length: greeting.count },\n (_unused, index) => \\`hello \\${greeting.name} #\\${index + 1}\\`,\n);\n\nfor (const line of lines) {\n console.log(line);\n}\n`;\n\n// Step 1: compile TypeScript to JavaScript inside the sandbox.\nconst compiled = await tools.compileSource({\n sourceText: typeScriptSource,\n compilerOptions: { module: \"ESNext\", target: \"ES2022\" },\n});\n\nif (!compiled.success) {\n const messages = compiled.diagnostics.map((d) => d.message);\n throw new Error(`TypeScript compile failed:\\n${messages.join(\"\\n\")}`);\n}\n\nconsole.log(\"Compiled TypeScript to JavaScript inside the sandbox.\");\n\n// Step 2: run the emitted JavaScript inside the sandbox.\nconst rt = await NodeRuntime.create();\ntry {\n const result = await rt.exec(compiled.outputText ?? \"\");\n console.log(\"exitCode:\", result.exitCode);\n console.log(\"guest stdout:\\n\" + result.stdout.trimEnd());\n} finally {\n await rt.dispose();\n}\n\n// Step 3: type-check a snippet that has a type error inside the sandbox.\nconst typeCheck = await tools.typecheckSource({\n sourceText: `const total: number = \"not a number\";`,\n});\n\nconsole.log(\"type check success:\", typeCheck.success);\nfor (const diagnostic of typeCheck.diagnostics) {\n console.log(\n ` ${diagnostic.category} TS${diagnostic.code} (line ${diagnostic.line}): ${diagnostic.message}`,\n );\n}\n\nif (typeCheck.success) {\n throw new Error(\"Expected the ill-typed snippet to fail type checking.\");\n}\n\nconsole.log(\"OK: TypeScript compiled and type-checked inside the sandbox.\");\n```\n\n*[See Full Example](https://github.com/rivet-dev/secure-exec/tree/main/examples/docs/feat-typescript)*\n\nPrints:\n\n```\nCompiled TypeScript to JavaScript inside the sandbox.\nexitCode: 0\nguest stdout:\nhello secure-exec #1\nhello secure-exec #2\nhello secure-exec #3\ntype check success: false\n error TS2322 (line 1): Type 'string' is not assignable to type 'number'.\nOK: TypeScript compiled and type-checked inside the sandbox.\n```\n\nEach diagnostic is structured (`code`, `category`, `message`, and a `line`/`column` when available), and `success` is `false` whenever any diagnostic is an error, so you can branch on results without parsing compiler text.\n\n## Compile a tsconfig.json project\n\nTo compile a whole project, seed a `tsconfig.json` and its sources with `files` (keyed by absolute guest path), then call `compileProject`. You can also project host directories into the VM with `mounts` instead of inlining them.\n\n```ts\nimport { createTypeScriptTools } from \"@secure-exec/typescript\";\n\nconst tools = createTypeScriptTools({\n files: {\n \"/root/tsconfig.json\": JSON.stringify({\n compilerOptions: { strict: true, target: \"ES2022\", module: \"ESNext\" },\n include: [\"src\"],\n }),\n \"/root/src/index.ts\": \"export const answer: number = 42;\\n\",\n },\n});\n\n// Compile every file the tsconfig includes, emitting into the VM filesystem.\nconst compiled = await tools.compileProject({ cwd: \"/root\" });\nconsole.log(\"project compiled:\", compiled.success);\nconsole.log(\"emitted:\", compiled.emittedFiles);\n\n// Or type-check only, without emitting any output.\nconst checked = await tools.typecheckProject({ cwd: \"/root\" });\nconsole.log(\"project type-checks:\", checked.success);\n```\n\n`compileProject` emits into the VM's virtual filesystem (`emittedFiles` lists the paths written). To pull that output back to the host, run the compile on a `NodeRuntime` directly and read the files with `rt.readFile`.\n\n## Bounding untrusted compiles\n\n`compileSource`/`typecheckSource` manage their own VM, so the compile is already contained. To put a wall-clock bound on running the *emitted* output (or your own compiler driver), run it on a `NodeRuntime` with a `timeout` or `AbortSignal`:\n\n```ts\nconst emitted = await tools.compileSource({ sourceText });\n\nconst rt = await NodeRuntime.create();\ntry {\n const out = await rt.exec(emitted.outputText ?? \"\", {\n timeout: 5_000,\n signal: AbortSignal.timeout(10_000),\n });\n console.log(out.exitCode);\n} finally {\n await rt.dispose();\n}\n```\n\nOn timeout or abort the guest process is killed inside the VM, so a runaway compile can never hang the host.","src/content/docs/docs/features/typescript.mdx","a39e1b84d785d895","docs/sdks/rust",{"id":266,"data":268,"body":274,"filePath":275,"digest":276,"deferredRender":16},{"title":269,"description":270,"editUrl":16,"head":271,"template":18,"sidebar":272,"pagefind":16,"draft":20},"Rust SDK","Install the Secure Exec Rust client and find its generated docs.rs reference.",[],{"hidden":20,"attrs":273},{},"import { LinkCard } from '@astrojs/starlight/components';\n\nThe `secure-exec-client` crate is the Rust SDK. It speaks the same sidecar wire protocol as the TypeScript client, so every capability reachable from `secure-exec` is also reachable from Rust through `SidecarProcess`.\n\n## Install\n\n```bash\ncargo add secure-exec-client\n```\n\nOr add it to `Cargo.toml`:\n\n```toml\n[dependencies]\nsecure-exec-client = \"*\"\n```\n\n## API reference\n\nThe full reference is generated with rustdoc and published to docs.rs. Use it as the source of truth for signatures and types.\n\n\u003CLinkCard\n title=\"secure-exec-client on docs.rs\"\n description=\"Generated rustdoc for the Rust client crate.\"\n href=\"https://docs.rs/secure-exec-client\"\n/>","src/content/docs/docs/sdks/rust.mdx","196d9503b11a1da6","docs/sdks/typescript",{"id":277,"data":279,"body":285,"filePath":286,"digest":287,"deferredRender":16},{"title":280,"description":281,"editUrl":16,"head":282,"template":18,"sidebar":283,"pagefind":16,"draft":20},"TypeScript SDK","Install the Secure Exec TypeScript SDK and find its generated API reference.",[],{"hidden":20,"attrs":284},{},"import { LinkCard } from '@astrojs/starlight/components';\n\nThe `secure-exec` package is the TypeScript SDK. It exports `NodeRuntime`, the batteries-included entry point for booting a virtualized VM and running guest JavaScript, plus the types describing its options and results.\n\n## Install\n\n```bash\nnpm install secure-exec\n```\n\n```ts\nimport { NodeRuntime } from \"secure-exec\";\n\nconst rt = await NodeRuntime.create();\ntry {\n const { stdout } = await rt.exec(\"console.log('hi', 1 + 1)\");\n console.log(stdout);\n} finally {\n await rt.dispose();\n}\n```\n\n## API reference\n\nThe full type-level reference is generated from the source with TypeDoc and is the source of truth for every export, method, and option.\n\n\u003CLinkCard\n title=\"TypeScript API Reference\"\n description=\"Generated TSDoc for the secure-exec package.\"\n href=\"/api\"\n/>","src/content/docs/docs/sdks/typescript.mdx","92737a1e8e217a10","docs/use-cases/code-mode",{"id":288,"data":290,"body":296,"filePath":297,"digest":298,"deferredRender":16},{"title":291,"description":292,"editUrl":16,"head":293,"template":18,"sidebar":294,"pagefind":16,"draft":20},"Code Mode (MCP)","Give AI agents a single code-execution tool instead of individual MCP tools. The LLM writes code that chains tool calls, executed safely in Secure Exec.",[],{"hidden":20,"attrs":295},{},"import { Aside, LinkCard } from '@astrojs/starlight/components';\n\n\u003CLinkCard title=\"Example on GitHub\" href=\"https://github.com/rivet-dev/secure-exec/tree/main/examples/docs/uc-code-mode\" description=\"Full working example: the LLM chains real host-tool calls in one sandboxed run and returns a structured result.\" />\n\nInstead of calling MCP tools one at a time, Code Mode lets the LLM write JavaScript that orchestrates everything in one go, run safely in a V8 sandbox by Secure Exec.\n\n\u003CAside type=\"tip\">\n [MCP Toolkit](https://mcp-toolkit.nuxt.dev/advanced/code-mode) provides a premade Code Mode library powered by Secure Exec: `experimental_codeMode: true`. We recommend trying it first. The rest of this page covers how to implement Code Mode yourself.\n\u003C/Aside>\n\n## Why Code Mode\n\n- **[81% less token overhead](https://x.com/hugorcd/status/2034616192225407273)**: With 50 tools, replacing per-call tool descriptions with a single code-execution tool cuts tool description tokens by 81%\n- **Fewer round-trips**: Chain multiple tool calls, conditionals, and data transformations in a single execution\n- **Real control flow**: Loops, branching, and `Promise.all`, not a chain of isolated tool calls\n- **One structured result**: The LLM returns a single JSON value via `globalThis.__return()`, decoded on the host as `result.value`\n\n## How it works\n\n1. Register your host tools on the host with `NodeRuntime.create({ tools })`. Each becomes a named command inside the sandbox.\n2. Give the LLM one tool (\"execute code\") and feed its generated JavaScript to `rt.run()`.\n3. The generated code invokes your tools by name. Each call round-trips out of the sandbox, runs the tool's host `handler`, and the handler's return value comes back to the guest.\n4. The guest hands a single structured result back to the host with `globalThis.__return(value)`, which `rt.run()` decodes as `result.value`.\n\nHost tools are the heart of Code Mode. The handlers run on the host, never in the sandbox, so the guest gets controlled, named capabilities (the kind an AI agent calls as tools) without being granted the underlying access. Registering tools auto-grants the `tool` permission scope; pass your own `permissions.tool` policy to gate individual tools.\n\n## Register the host tools\n\nEach tool has a `description`, a JSON Schema `inputSchema`, and a `handler`. The handler receives the parsed input and returns a JSON-serializable result.\n\n```ts\nimport { NodeRuntime } from \"secure-exec\";\n\n// Register the host tools. These handlers run on the HOST, not in the sandbox.\n// In a real app each handler would hit a database, an API, or a service; here we\n// keep them small and deterministic so the example is easy to follow.\nconst rt = await NodeRuntime.create({\n tools: {\n \"get-weather\": {\n description: \"Look up the current temperature for a city\",\n inputSchema: {\n type: \"object\",\n properties: { city: { type: \"string\" } },\n required: [\"city\"],\n },\n handler: ({ city }: { city: string }) => {\n const table: Record\u003Cstring, { temp_f: number }> = {\n \"San Francisco\": { temp_f: 61 },\n Tokyo: { temp_f: 75 },\n };\n return table[city] ?? { temp_f: null };\n },\n },\n calculate: {\n description: \"Evaluate a simple arithmetic expression\",\n inputSchema: {\n type: \"object\",\n properties: { expression: { type: \"string\" } },\n required: [\"expression\"],\n },\n handler: ({ expression }: { expression: string }) => {\n return { result: Number(eval(expression)) };\n },\n },\n },\n});\n```\n\n## The agent's generated code\n\nThe agent then generates code like this (call it `llmGeneratedCode`). The guest calls each tool with the `callHostTool(name, input)` global, which resolves with the host handler's return value. It chains three tool calls with real control flow (`Promise.all`, arithmetic, branching) in one execution, then returns a single structured result:\n\n```ts\n// Imagine this string was written by the LLM. It chains three host-tool calls\n// with real control flow (Promise.all, arithmetic, branching) in one execution,\n// then hands a single structured result back to the host. callHostTool resolves\n// with the host handler's return value.\nconst llmGeneratedCode = `\nconst [sf, tokyo] = await Promise.all([\n callHostTool(\"get-weather\", { city: \"San Francisco\" }),\n callHostTool(\"get-weather\", { city: \"Tokyo\" }),\n]);\n\nconst diffF = Math.abs(sf.temp_f - tokyo.temp_f);\nconst diffC = await callHostTool(\"calculate\", { expression: \\`\\${diffF} * 5 / 9\\` });\n\nconsole.log(\"chained 3 tool calls in one sandbox execution\");\n\nglobalThis.__return({\n san_francisco: sf,\n tokyo: tokyo,\n difference: { fahrenheit: diffF, celsius: diffC.result },\n warmer: sf.temp_f > tokyo.temp_f ? \"San Francisco\" : \"Tokyo\",\n});\n`;\n```\n\n## Run it and read the result\n\nRun the LLM's code in one sandboxed pass and read back the structured result:\n\n```ts\ntry {\n // rt.run() executes the guest code and decodes whatever it passes to\n // globalThis.__return(), while still capturing stdout/stderr/exitCode.\n const result = await rt.run(llmGeneratedCode, { timeout: 5000 });\n\n console.log(\"exitCode:\", result.exitCode);\n console.log(\"stdout:\", result.stdout.trim());\n console.log(\"structured result:\", JSON.stringify(result.value, null, 2));\n} finally {\n await rt.dispose();\n}\n```\n\n*[See Full Example](https://github.com/rivet-dev/secure-exec/tree/main/examples/docs/uc-code-mode)*\n\nThree tool calls, one sandbox execution, zero extra LLM round-trips. Running it prints:\n\n```text\nexitCode: 0\nstdout: chained 3 tool calls in one sandbox execution\nstructured result: {\n \"san_francisco\": {\n \"temp_f\": 61\n },\n \"tokyo\": {\n \"temp_f\": 75\n },\n \"difference\": {\n \"fahrenheit\": 14,\n \"celsius\": 7.777777777777778\n },\n \"warmer\": \"Tokyo\"\n}\n```\n\n## Further reading\n\n- [Complete Code Mode implementation guide](https://mcp-toolkit.nuxt.dev/advanced/code-mode): end-to-end Code Mode walkthrough using MCP Toolkit\n- [Cloudflare Code Mode blog post](https://blog.cloudflare.com/code-mode/)\n- [AI Agent Code Exec](/use-cases/ai-agent-code-exec) for simpler single-tool execution patterns","src/content/docs/docs/use-cases/code-mode.mdx","4d759b283e9508eb","docs/use-cases/ai-agent-code-exec",{"id":299,"data":301,"body":307,"filePath":308,"digest":309,"deferredRender":16},{"title":302,"description":303,"editUrl":16,"head":304,"template":18,"sidebar":305,"pagefind":16,"draft":20},"AI Agent Code Exec","Give AI agents a secure code-execution tool that runs untrusted code in a sandbox and returns structured results.",[],{"hidden":20,"attrs":306},{},"import { LinkCard } from '@astrojs/starlight/components';\n\n\u003CLinkCard title=\"Example on GitHub\" href=\"https://github.com/rivet-dev/secure-exec/tree/main/examples/docs/uc-ai-agent-code-exec\" description=\"Full working example that runs untrusted code and captures its result.\" />\n\nGive your agent a code-execution tool that runs untrusted, model-generated code in a fully virtualized VM. The agent writes code, it runs inside the kernel isolation boundary with no access to the host, and you get back its stdout and a structured return value.\n\n## Run untrusted JavaScript and capture a result\n\n`NodeRuntime.create()` boots a sandboxed VM. `rt.run()` executes the guest code and decodes whatever it passes to `globalThis.__return()`, while still capturing `stdout`, `stderr`, and `exitCode`. Use `rt.exec()` when you only need the captured output streams.\n\nThe guest code runs as a standard ES module (top-level `await` and `import` work), but it can only see the virtual filesystem and kernel-mediated syscalls, and it cannot reach the host machine.\n\n```ts AI Agent Code Exec\nimport { NodeRuntime } from \"secure-exec\";\n\n// Imagine this string came from an AI agent. We never trust it: it runs fully\n// sandboxed inside the secure-exec VM, with no access to the host machine.\nconst untrustedCode = `\nconst fib = [0, 1];\nwhile (fib.length \u003C 20) {\n fib.push(fib[fib.length - 1] + fib[fib.length - 2]);\n}\nconsole.log(\"computed\", fib.length, \"fibonacci numbers\");\n// Hand a JSON-serializable value back to the host.\nglobalThis.__return({ fibonacci: fib, sum: fib.reduce((a, b) => a + b, 0) });\n`;\n\nconst rt = await NodeRuntime.create();\ntry {\n // rt.run() executes the guest code and decodes whatever it passes to\n // globalThis.__return(), while still capturing stdout/stderr/exitCode.\n const result = await rt.run\u003C{ fibonacci: number[]; sum: number }>(\n untrustedCode,\n { timeout: 5000 },\n );\n\n console.log(\"exitCode:\", result.exitCode);\n console.log(\"stdout:\", result.stdout.trim());\n console.log(\"returned value:\", JSON.stringify(result.value));\n\n // The sandbox presents normal Node semantics, but the code cannot touch the\n // host: it only ever sees the virtual filesystem and kernel-mediated syscalls.\n const escapeAttempt = await rt.exec(\n `import os from \"node:os\";\\nconsole.log(\"guest hostname:\", os.hostname());`,\n { timeout: 5000 },\n );\n console.log(\"\\nescape attempt exitCode:\", escapeAttempt.exitCode);\n console.log(\"escape attempt stdout:\", escapeAttempt.stdout.trim());\n} finally {\n await rt.dispose();\n}\n```\n\n*[See Full Example](https://github.com/rivet-dev/secure-exec/tree/main/examples/docs/uc-ai-agent-code-exec)*\n\nRunning this prints the captured stdout and the decoded return value, and shows that the guest only ever sees the sandbox:\n\n```\nexitCode: 0\nstdout: computed 20 fibonacci numbers\nreturned value: {\"fibonacci\":[0,1,1,2,3,5,8,13,21,34,55,89,144,233,377,610,987,1597,2584,4181],\"sum\":10945}\n\nescape attempt exitCode: 0\nescape attempt stdout: guest hostname: secure-exec\n```\n\n## Wiring it into an agent tool\n\nA single `NodeRuntime` instance can run many programs. Each `run()` / `exec()` call executes a fresh guest process. To expose this as a tool to your agent framework, hold one runtime for the session and call `rt.run(code)` from the tool's handler, returning `{ stdout, value, exitCode }` to the model. Pass a `timeout` (in milliseconds) per call to bound runaway code, and call `rt.dispose()` when the session ends.\n\n## Sandboxing untrusted code\n\n`NodeRuntime.create()` denies network by default and allows the virtualized `fs`, `childProcess`, `process`, and `env` scopes; any `permissions` you pass merges over that default, so an omitted scope keeps its default rather than being denied. Pass a partial policy (for example `{ network: \"allow\" }` to opt into the network, or a rule set on `fs` to tighten filesystem access) to adjust individual scopes.\n\n```ts\nimport { NodeRuntime } from \"secure-exec\";\n\n// network is already denied by default; this opts it back in while the other\n// scopes keep their defaults.\nconst rt = await NodeRuntime.create({\n permissions: { network: \"allow\" },\n});\n```\n\n\u003CLinkCard title=\"Permissions\" href=\"/docs/features/permissions\" description=\"The full policy model: scopes, rule sets, and how partial policies merge over the secure default.\" />\n\nYou can also constrain the run with `env` and `cwd` on `NodeRuntime.create()`, and `env`, `cwd`, `stdin`, and `timeout` on each `run()` / `exec()` call.","src/content/docs/docs/use-cases/ai-agent-code-exec.mdx","1f5f39857671d3e0","docs/use-cases/dev-servers",{"id":310,"data":312,"body":318,"filePath":319,"digest":320,"deferredRender":16},{"title":313,"description":314,"editUrl":16,"head":315,"template":18,"sidebar":316,"pagefind":16,"draft":20},"Dev Servers","Run user-provided server-style code (HTTP servers, request handlers) inside a secure isolate.",[],{"hidden":20,"attrs":317},{},"import { LinkCard } from '@astrojs/starlight/components';\n\n\u003CLinkCard title=\"Example on GitHub\" href=\"https://github.com/rivet-dev/secure-exec/tree/main/examples/docs/uc-dev-servers\" description=\"Full working example that boots a long-running HTTP server inside a sandboxed isolate and drives host requests into it.\" />\n\nLet users run their own server-style code inside a sandboxed isolate. A guest program can boot a real `node:http` server, bind a loopback port owned by the kernel, and serve requests, all without touching the host machine.\n\nSecure Exec keeps a guest server running and forwards host requests into it. `spawn()` starts a long-running guest program and returns a process handle immediately, without waiting for it to exit. `fetch(port, { method, path, headers, body })` drives an HTTP request from the host into the guest server listening on that port, through the kernel socket table, and returns the response. The request and response never leave the VM, so this works even when guest network egress is denied.\n\n## Spawn a server and drive host requests into it\n\nThe guest boots an HTTP server on loopback and stays alive serving requests. The host spawns it, blocks on `waitForListener()` until the server is accepting connections, drives a request into it, then kills the process and waits for it to exit.\n\n```ts\nimport { NodeRuntime } from \"secure-exec\";\n\n// A user's \"dev server\": untrusted, long-running server-style code. It boots a\n// real node:http server and keeps serving until it is killed, all inside the\n// secure-exec VM with no access to the host machine.\nconst devServer = `\nimport http from \"node:http\";\n\n// Start the user's server, exactly as they wrote it.\nconst app = http.createServer((req, res) => {\n if (req.url === \"/health\") {\n res.writeHead(200, { \"content-type\": \"application/json\" });\n res.end(JSON.stringify({ ok: true }));\n return;\n }\n res.writeHead(200, { \"content-type\": \"text/plain\" });\n res.end(\"hello from the sandboxed dev server\");\n});\n\n// Listen on loopback inside the VM. The kernel owns this socket; it never\n// touches a real host port. The process stays alive serving requests until the\n// host kills it.\napp.listen(3000, \"127.0.0.1\", () => {\n console.log(\"server listening on 127.0.0.1:3000\");\n});\n`;\n\n// The guest binds a loopback port, so opt in to networking. NodeRuntime.create()\n// denies network by default; permissions merge over that secure default.\nconst runtime = await NodeRuntime.create({ permissions: { network: \"allow\" } });\n\ntry {\n\t// spawn() starts the server as a long-running guest process and returns a\n\t// handle immediately, without waiting for it to exit.\n\tconst server = await runtime.spawn(devServer, {\n\t\tonStdout: (chunk) => process.stdout.write(new TextDecoder().decode(chunk)),\n\t});\n\tconsole.log(\"spawned guest server, pid:\", server.pid);\n\n\ttry {\n\t\t// Block until the guest is actually accepting connections on the port,\n\t\t// then drive requests into it.\n\t\tawait runtime.waitForListener({ port: 3000 });\n\n\t\t// Drive a real host->guest request into the running server.\n\t\tconst health = await runtime.fetch(3000, { path: \"/health\" });\n\t\tconsole.log(\"health check ->\", health.status, JSON.stringify(health.body));\n\n\t\tconst res = await runtime.fetch(3000, { method: \"GET\", path: \"/\" });\n\t\tconsole.log(\"GET / ->\", res.status, JSON.stringify(res.body));\n\n\t\tconsole.log(\n\t\t\t\"RESULT \" + JSON.stringify({ status: res.status, body: res.body }),\n\t\t);\n\t} finally {\n\t\t// Tear the server down and wait for the guest process to exit.\n\t\tserver.kill();\n\t\tawait server.wait();\n\t\tconsole.log(\"server stopped\");\n\t}\n} finally {\n\t// Tear down the VM and release the sidecar.\n\tawait runtime.dispose();\n}\n```\n\n*[See Full Example](https://github.com/rivet-dev/secure-exec/tree/main/examples/docs/uc-dev-servers)*\n\nRunning it spawns the server, drives host requests into it, and tears it down:\n\n```\nspawned guest server, pid: 1000000\nserver listening on 127.0.0.1:3000\nhealth check -> 200 \"{\\\"ok\\\":true}\"\nGET / -> 200 \"hello from the sandboxed dev server\"\nRESULT {\"status\":200,\"body\":\"hello from the sandboxed dev server\"}\nserver stopped\n```\n\nThe guest owns the server process, the application code, and the loopback socket, while the host stays in control of the lifecycle through the process handle (`kill()`, `wait()`) and `dispose()`. The kernel mediates the socket, so the guest never binds a real host port.\n\nThis is useful for platforms that let users write and preview server-side code (live coding environments, serverless playgrounds, educational tools) without giving them access to the host machine.","src/content/docs/docs/use-cases/dev-servers.mdx","745d1bf6404d149a","docs/use-cases/plugin-systems",{"id":321,"data":323,"body":329,"filePath":330,"digest":331,"deferredRender":16},{"title":324,"description":325,"editUrl":16,"head":326,"template":18,"sidebar":327,"pagefind":16,"draft":20},"Plugin Systems","Run user-authored plugins in isolation with explicit permissions.",[],{"hidden":20,"attrs":328},{},"Let users upload scripts or extensions without risking your host. The host controls what plugin code runs, what capabilities are available, and what structured data comes back.\n\n## Run a plugin in isolation\n\nThe host owns the plugin source and the input. Run the plugin with `run()` inside a sandboxed VM and get a structured value back: the guest calls `globalThis.__return(value)` with any JSON-serializable value, and that value is decoded on the host as `result.value`.\n\nThe plugin below gets filesystem access but no network access. The guest proves it cannot reach the network, then transforms the host-supplied input.\n\n```ts Plugin Runner\nimport { NodeRuntime } from \"secure-exec\";\n\n// Boot a sandboxed VM for running untrusted plugin code. The plugin can use\n// the filesystem, but network access is denied. (childProcess/process stay\n// allowed because the kernel spawns the guest `node` process to run the\n// plugin - denying it would block the runtime itself.)\nconst runtime = await NodeRuntime.create({\n permissions: {\n fs: \"allow\",\n network: \"deny\",\n childProcess: \"allow\",\n process: \"allow\",\n env: \"allow\",\n },\n});\n\ntry {\n // The host owns the plugin source and the input. Here the plugin is a\n // title-case transformer; in a real system it would be uploaded by a user.\n const pluginSource = `\n function transform(input, options = {}) {\n const words = String(input)\n .split(/\\\\s+/)\n .filter(Boolean)\n .map((w) => w.charAt(0).toUpperCase() + w.slice(1).toLowerCase());\n return (options.prefix ?? \"\") + words.join(\" \");\n }\n const manifest = { name: \"title-case\", version: \"1.0.0\" };\n `;\n\n const input = \"hello from plugin land\";\n const options = { prefix: \"Plugin says: \" };\n\n // Run the plugin in isolation and get a structured value back via run().\n // The guest calls __return() with a JSON-serializable value, decoded on the\n // host as result.value. The plugin also proves it cannot reach the network.\n const { value, stdout, exitCode } = await runtime.run\u003C{\n manifest: { name: string; version: string };\n output: string;\n networkBlocked: boolean;\n }>(`\n ${pluginSource}\n\n console.log(\"running plugin:\", manifest.name);\n\n let networkBlocked = false;\n try {\n await fetch(\"http://example.com\");\n } catch {\n networkBlocked = true;\n }\n\n __return({\n manifest,\n output: transform(${JSON.stringify(input)}, ${JSON.stringify(options)}),\n networkBlocked,\n });\n `);\n\n console.log(\"guest stdout:\", stdout.trim());\n console.log(\"exit code:\", exitCode);\n console.log(\"plugin name:\", value?.manifest.name);\n console.log(\"plugin version:\", value?.manifest.version);\n console.log(\"plugin output:\", value?.output);\n console.log(\"network blocked:\", value?.networkBlocked);\n} finally {\n await runtime.dispose();\n}\n```\n\n*[See Full Example](https://github.com/rivet-dev/secure-exec/tree/main/examples/docs/uc-plugin-systems)*\n\nThe plugin executes inside the kernel isolation boundary with only the capabilities you granted (network access is denied here), and the host gets back structured data via `__return()` rather than direct access to plugin internals.\n\nYou can combine this with [TypeScript](/docs/features/typescript) to type-check uploaded plugin code before enabling it.\n\n## Let plugins call curated host tools\n\nDenying a capability outright is one option, but most plugin systems need the opposite: the plugin must reach a few host capabilities, just not the raw underlying access. The canonical pattern is host tools. You register a narrow set of named tools whose handlers run on the host, and the untrusted plugin invokes them by name. The plugin never gets the database connection, the secret, or the network socket behind the tool; it only gets the curated surface you chose to expose.\n\nRegister host tools with the `tools` option on `create()` (or add them to a live runtime with `rt.registerTools()`). Each tool becomes a named command inside the VM, and the plugin invokes it with the `callHostTool(name, input)` global, which resolves with the host handler's return value.\n\n```ts Host Tools\nimport { NodeRuntime } from \"secure-exec\";\n\n// Register curated host tools. Their handlers run on the host, so the plugin\n// reaches these capabilities only through the tool surface you expose - never\n// the underlying database, secrets, or network behind them.\nconst runtime = await NodeRuntime.create({\n tools: {\n lookupUser: {\n description: \"Look up a user by id\",\n inputSchema: {\n type: \"object\",\n properties: { id: { type: \"string\" } },\n required: [\"id\"],\n },\n // Runs on the host. In a real system this would hit your database.\n handler: ({ id }: { id: string }) => ({\n id,\n name: id === \"u_1\" ? \"Ada Lovelace\" : \"Unknown\",\n }),\n },\n },\n});\n\ntry {\n // The untrusted plugin reaches the host capability only through callHostTool,\n // which resolves with the handler's return value.\n const { value } = await runtime.run\u003C{ id: string; name: string }>(`\n const user = await callHostTool(\"lookupUser\", { id: \"u_1\" });\n __return(user);\n `);\n\n console.log(\"looked-up user:\", value?.name);\n} finally {\n await runtime.dispose();\n}\n```\n\n*[See Full Example](https://github.com/rivet-dev/secure-exec/tree/main/examples/docs/uc-code-mode)*\n\nThis is safe because the plugin reaches host capability only through the curated tool surface, never the underlying access behind it. The `tool` permission scope gates invocation: when you pass `tools` and set no `tool` policy, the scope is granted so the registered tools are invocable, but you can supply your own `permissions.tool` policy to gate individual tools.\n\nSee [Bindings](/docs/features/bindings) for the full guide, including input schemas, command aliases, and worked examples.","src/content/docs/docs/use-cases/plugin-systems.mdx","ed5737979858df78"] \ No newline at end of file +[["Map",1,2,9,10],"meta::meta",["Map",3,4,5,6,7,8],"astro-version","5.18.2","content-config-digest","56395185ffd4ce46","astro-config-digest","{\"root\":{},\"srcDir\":{},\"publicDir\":{},\"outDir\":{},\"cacheDir\":{},\"site\":\"https://secureexec.dev\",\"compressHTML\":true,\"base\":\"/\",\"trailingSlash\":\"ignore\",\"output\":\"static\",\"scopedStyleStrategy\":\"attribute\",\"build\":{\"format\":\"directory\",\"client\":{},\"server\":{},\"assets\":\"_astro\",\"serverEntry\":\"entry.mjs\",\"redirects\":true,\"inlineStylesheets\":\"auto\",\"concurrency\":1},\"server\":{\"open\":false,\"host\":true,\"port\":4322,\"streaming\":true,\"allowedHosts\":[]},\"redirects\":{},\"image\":{\"endpoint\":{\"route\":\"/_image\"},\"service\":{\"entrypoint\":\"astro/assets/services/sharp\",\"config\":{}},\"domains\":[],\"remotePatterns\":[],\"responsiveStyles\":false},\"devToolbar\":{\"enabled\":true},\"markdown\":{\"syntaxHighlight\":false,\"shikiConfig\":{\"langs\":[],\"langAlias\":{},\"theme\":\"github-dark\",\"themes\":{},\"wrap\":false,\"transformers\":[]},\"remarkPlugins\":[null,null,null,null,null],\"rehypePlugins\":[null,[null,{\"strategy\":\"pre-mermaid\",\"mermaidConfig\":{\"theme\":\"dark\"}}],null,null,null,null],\"remarkRehype\":{},\"gfm\":true,\"smartypants\":true},\"security\":{\"checkOrigin\":true,\"allowedDomains\":[],\"actionBodySizeLimit\":1048576},\"env\":{\"schema\":{},\"validateSecrets\":false},\"experimental\":{\"clientPrerender\":false,\"contentIntellisense\":false,\"headingIdCompat\":false,\"preserveScriptOrder\":false,\"liveContentCollections\":false,\"csp\":false,\"staticImportMetaEnv\":false,\"chromeDevtoolsWorkspace\":false,\"failOnPrerenderConflict\":false,\"svgo\":false},\"legacy\":{\"collections\":false}}","docs",["Map",11,12,20,21,28,29,9,36,43,44,51,52,59,60,67,68,75,76,83,84,91,92,99,100,107,108,115,116,123,124,131,132,139,140,147,148,155,156,163,164,171,172,179,180,187,188,195,196,203,204,211,212,219,220,227,228,235,236],"docs/architecture",{"id":11,"data":13,"body":16,"filePath":17,"digest":18,"deferredRender":19},{"title":14,"description":15},"Architecture","A short overview of the Secure Exec architecture, with a link to the canonical agentOS architecture docs.","Secure Exec runs untrusted guest code inside a fully virtualized VM whose kernel services every guest syscall. At a glance:\n\n- **Kernel-owned VM**: A kernel owns the virtual filesystem, process table, and socket table, plus pipes, PTYs, permission policy, and DNS. There is no real host filesystem, host socket, or host process available to the guest.\n- **Guest runs in an executor**: Guest JavaScript runs in a V8 isolate and other guest code runs in a WASM executor, holding no real host capabilities of their own.\n- **Sidecar mediates every syscall**: A trusted sidecar is the enforcement point. Every guest syscall flows through kernel-owned paths it controls, where policy and limits are checked.\n- **Normal Linux semantics**: The VM presents POSIX-like behavior to guest programs, so normal tools run unmodified while staying fully virtualized.\n\n## Full reference\n\nThe canonical, in-depth architecture reference, including packages, crates, trust boundaries, and syscall paths, is owned by agentOS.\n\n\u003CCard title=\"agentOS: Architecture\" href=\"https://agentos-sdk.dev/docs/architecture\">\n The complete architecture reference, including components, trust boundary, and syscall paths.\n\u003C/Card>","src/content/docs/docs/architecture.mdx","60be6731b4504e40",true,"docs/benchmarks",{"id":20,"data":22,"body":25,"filePath":26,"digest":27,"deferredRender":19},{"title":23,"description":24},"Benchmarks","Cold start, warm execution, and reuse fast-path measurements for the Secure Exec SDK.","These numbers measure the public `secure-exec` SDK paths that consumers actually use. The cold start matrix (`packages/benchmarks/coldstart.bench.ts`) times the full journey from booting a runtime to running guest code, and compares three ways of provisioning a runtime against how much you can reuse.\n\n\u003CNote>Numbers below are a full run from June 19, 2026 on the hardware listed under [Methodology](#methodology). They are indicative at this sample count (5 iterations + 1 warmup), not statistically tight. Reproduce them with the commands in [Running the benchmarks](#running-the-benchmarks).\u003C/Note>\n\n## Scenarios\n\n- **owned-sidecar**: `NodeRuntime.create()` boots a fresh sidecar process for each runtime. This is the default, fully isolated path (see [Process Isolation](/docs/architecture)).\n- **shared-sidecar**: one sidecar process is created once and reused across many runtimes, instead of spawning a fresh sidecar per runtime. Sidecar setup is measured separately and excluded from cold start, so this isolates the per-runtime cost. (Sharing a sidecar is a reuse fast path: spawn one `Sidecar` and pass it to `NodeRuntime.create({ sidecar })`, instead of the default `NodeRuntime.create()` path that owns a fresh sidecar per runtime.)\n- **resident-runner**: a shared sidecar plus a resident runner, so repeated small snippets reuse one live guest Node process instead of starting a new one each time.\n\n## Cold vs warm\n\nEach scenario reports two latencies:\n\n- **Cold**: provisioning the runtime and running the first guest snippet end to end.\n- **Warm**: running a second snippet on the same runtime, after it is already up.\n\nA single sequential runtime (batch size 1) gives the cleanest picture:\n\n| Scenario | Cold mean | Cold p50 | Warm mean | Warm p50 |\n| --- | ---: | ---: | ---: | ---: |\n| owned-sidecar | 772.88ms | 771.96ms | 452.68ms | 452.37ms |\n| shared-sidecar | 774.17ms | 774.50ms | 457.19ms | 452.75ms |\n| resident-runner | 351.00ms | 349.56ms | 1.27ms | 1.27ms |\n\nThe headline result is the resident runner: once the live guest process exists, a warm snippet runs in about **1.3ms**, roughly 350x faster than a warm execution that still has to stand up a guest process. Owned and shared sidecars cost about the same per runtime when run sequentially, because the sidecar process itself is cheap to spawn (around 3ms); sharing it mainly matters under concurrency.\n\n## Where the cold-start time goes\n\nBreaking down a single owned-sidecar cold start (batch 1, sequential, p50 per phase):\n\n| Phase | p50 |\n| --- | ---: |\n| sidecar_spawn | 2.78ms |\n| session_open | 2.34ms |\n| vm_create | 1.36ms |\n| vm_configure | 0.17ms |\n| runtime_mount_node | 2.71ms |\n| runtime_mount_wasm | 172.95ms |\n| runtime_create_total | 176.30ms |\n| first_exec | 596.26ms |\n| warm_exec | 452.37ms |\n\nTwo phases dominate: mounting the WASM command set (about 173ms) and the first guest execution (about 596ms, which includes bringing up the guest Node runtime). Spawning the sidecar, opening a session, and creating the VM together cost only a few milliseconds. This is why the resident runner wins so decisively: it pays the first-exec cost once and then reuses the live process.\n\n## Concurrency\n\nThe matrix also runs each scenario at larger batch sizes, both sequentially and concurrently (up to the host concurrency cap). Cold mean latency by batch size:\n\n| Scenario | Mode | b=1 | b=10 | b=50 | b=100 | b=200 |\n| --- | --- | ---: | ---: | ---: | ---: | ---: |\n| owned-sidecar | sequential | 772.88ms | 780.07ms | 777.49ms | 777.89ms | 778.28ms |\n| owned-sidecar | concurrent | 776.22ms | 1000.39ms | 1041.81ms | 1041.19ms | 1044.03ms |\n| shared-sidecar | sequential | 774.17ms | 627.58ms | 610.76ms | 619.24ms | 616.20ms |\n| shared-sidecar | concurrent | 775.66ms | 3493.51ms | 3197.96ms | 3187.99ms | 3235.65ms |\n| resident-runner | sequential | 351.00ms | 202.61ms | 187.92ms | 186.10ms | 189.76ms |\n| resident-runner | concurrent | 347.91ms | 205.00ms | 187.45ms | 187.07ms | 191.33ms |\n\nTakeaways:\n\n- **owned-sidecar** holds flat when sequential. Run concurrently, per-runtime cold time rises to about 1040ms as many runtimes mount their WASM command sets at once and contend for CPU. Each runtime still has its own sidecar, so they make progress in parallel.\n- **shared-sidecar** is efficient sequentially (around 610ms once the shared sidecar is warm) but degrades sharply under concurrency (3000ms or more), because one sidecar process serializes the heavy concurrent mount and first-exec work. Share a sidecar when work arrives sequentially or at low concurrency, not for bursty parallel fan-out.\n- **resident-runner** improves with batch size as the one-time runner creation amortizes, settling around 187ms cold and about 1.3ms warm regardless of mode.\n\n## Choosing a strategy\n\n- Need strong isolation and unpredictable, bursty load: use **owned-sidecar** (the default). Each runtime is its own crash and resource domain.\n- Running many short tasks back to back where a shared failure domain is acceptable: a **shared-sidecar** amortizes setup.\n- Running the same kind of small snippet over and over (for example an evaluation loop): a **resident-runner** turns a roughly 450ms warm execution into a roughly 1.3ms one.\n\nSee [Process Isolation](/docs/architecture) for what each of these shares and isolates.\n\n## Methodology\n\n```text\nCPU: 12th Gen Intel(R) Core(TM) i7-12700KF\nCores: 20 | Max concurrency: 16 | Max live runtimes: 8\nRAM: 62.6 GB | Node: v24.13.0\nIterations: 5 (+ 1 warmup)\nBatch sizes: 1, 10, 50, 100, 200\nScenarios: owned-sidecar, shared-sidecar, resident-runner\nSidecar: release build of secure-exec-sidecar\n```\n\nCold start is wall time from the start of runtime provisioning through the first guest execution. Warm is a second execution on the already-running runtime. For shared-sidecar, the one-time sidecar setup (around 4ms to 5ms) is measured separately and excluded from the per-runtime cold number. Phase timings (`sidecar_spawn`, `session_open`, `vm_create`, `runtime_mount_wasm`, `first_exec`, and the resident-runner phases) are recorded in the machine-readable JSON output.\n\n## Running the benchmarks\n\nBuild a release sidecar first for meaningful timings:\n\n```bash\ncargo build --release -p secure-exec-sidecar\n```\n\nRun the full suite:\n\n```bash\npnpm --dir packages/benchmarks bench\n```\n\nRun only the cold start matrix:\n\n```bash\nSECURE_EXEC_SIDECAR_BIN=\"$PWD/target/release/secure-exec-sidecar\" \\\n pnpm --silent --dir packages/benchmarks bench:coldstart \\\n > packages/benchmarks/results/coldstart-local.json \\\n 2> packages/benchmarks/results/coldstart-local.log\n```\n\nA quick smoke run keeps it to one iteration:\n\n```bash\nBENCH_BATCH_SIZES=1 \\\nBENCH_ITERATIONS=1 \\\nBENCH_WARMUP=0 \\\nBENCH_SCENARIOS=owned-sidecar,shared-sidecar,resident-runner \\\nSECURE_EXEC_SIDECAR_BIN=\"$PWD/target/release/secure-exec-sidecar\" \\\n pnpm --silent --dir packages/benchmarks bench:coldstart\n```","src/content/docs/docs/benchmarks.mdx","23f4a46fffecf7a1","docs/crash-course",{"id":28,"data":30,"body":33,"filePath":34,"digest":35,"deferredRender":19},{"title":31,"description":32},"Crash Course","A fast tour of Secure Exec: install, run code, capture output, and the core SDK concepts.","This is a fast, guided walk through the essentials: install the SDK, boot a\nruntime, run guest code, and capture its output. By the end you will understand\nthe core loop and know where to go for more.\n\n`NodeRuntime` is the entry point: it boots a virtualized VM and runs guest JavaScript end to end, secure by default (no host filesystem, network, or process access until you allow it) and with every `create()` option optional so you can start with zero setup.\n\nFor exact signatures and option shapes, see the\n[TypeScript SDK reference](/docs/sdks/typescript).\n\n## Install\n\n\u003CTabs>\n\n\u003CTab title=\"npm\">\n\n```bash\nnpm install secure-exec\n```\n\n\u003C/Tab>\n\n\u003CTab title=\"bun\">\n\n```bash\nbun add secure-exec\n```\n\n\u003C/Tab>\n\n\u003CTab title=\"pnpm\">\n\n```bash\npnpm add secure-exec\n```\n\n\u003C/Tab>\n\n\u003CTab title=\"yarn\">\n\n```bash\nyarn add secure-exec\n```\n\n\u003C/Tab>\n\n\u003C/Tabs>\n\n## Your first run\n\nThe core loop is always the same: create a runtime, run code, dispose it.\n\n```ts\nimport { NodeRuntime } from \"secure-exec\";\n\nconst rt = await NodeRuntime.create();\ntry {\n const { stdout } = await rt.exec(\"console.log('hi', 1 + 1)\");\n console.log(stdout); // \"hi 2\\n\"\n} finally {\n await rt.dispose();\n}\n```\n\n- **`NodeRuntime.create()`**: boots a fresh VM. Reuse one runtime across many runs.\n- **`rt.exec(code)`**: runs guest code as an ES module.\n- **`rt.dispose()`**: releases the VM and its sidecar. Always call it when done.\n\n*[See Full Example](https://github.com/rivet-dev/secure-exec/tree/main/examples/docs/sdk-overview)*\n\n## Capture output\n\n`exec()` returns the streams and exit code from the run.\n\n```ts\nconst { stdout, stderr, exitCode } = await rt.exec(`\n console.log(\"to stdout\");\n console.error(\"to stderr\");\n`);\nconsole.log(exitCode); // 0\n```\n\n`exitCode` is `0` on a clean exit and non-zero if the guest threw or was killed.\n\nRead more about [Output Capture](/docs/features/output-capture).\n\n## Return a value\n\nUse `run\u003CT>()` when you want a typed value back instead of parsing stdout. The\nguest returns it with `globalThis.__return(value)`.\n\n```ts\nconst { value } = await rt.run\u003C{ sum: number }>(`\n globalThis.__return({ sum: 2 + 40 });\n`);\nconsole.log(value?.sum); // 42\n```\n\nRead more about [Executing Code](/docs/features/executing-code).\n\n## Set a timeout\n\nPass a `timeout` so a runaway guest cannot run forever. The VM kills the process\nwhen the budget elapses.\n\n```ts\nconst result = await rt.exec(`while (true) {}`, { timeout: 1000 });\nconsole.log(result.exitCode); // non-zero: the guest was killed\n```\n\nRead more about [Resource Limits](/docs/features/resource-limits).\n\n## Where to go next\n\nYou now know the core loop. Each feature builds on it:\n\n- **[Executing Code](/docs/features/executing-code)**: `exec`, `run`, modules, and inputs.\n- **[Child Processes](/docs/features/child-processes)**: `spawn()` for long-running guest programs.\n- **[Resident Runner](/docs/features/resident-runner)**: keep a guest process alive for fast repeated runs.\n- **[Filesystem](/docs/features/filesystem)**: read, write, and seed the virtualized VFS.\n- **[NPM & Module Loading](/docs/features/module-loading)**: resolve real npm packages inside the VM.\n- **[Networking](/docs/features/networking)**: guest `fetch`, sockets, and driving HTTP into a guest server.\n- **[Bindings](/docs/features/bindings)**: expose curated host functions to guest code.\n- **[Permissions](/docs/features/permissions)**: grant network and other access over the secure default.\n- **[Runtime & Platform](/docs/features/runtime-platform)**: shape the env, cwd, and platform the guest sees.\n- **[TypeScript](/docs/features/typescript)**: compile and type-check inside the sandbox.","src/content/docs/docs/crash-course.mdx","33604db13724caa2",{"id":9,"data":37,"body":40,"filePath":41,"digest":42,"deferredRender":19},{"title":38,"description":39},"Introduction","Secure Exec: a fully virtualized runtime for executing untrusted code with zero host escapes.","A lightweight library for secure Node.js execution. No containers, no VMs — just\nnpm-compatible sandboxing out of the box.","src/content/docs/docs/index.mdx","fb460841facd4766","docs/nodejs-compatibility",{"id":43,"data":45,"body":48,"filePath":49,"digest":50,"deferredRender":19},{"title":46,"description":47},"Node.js Compatibility","Which node builtins guest code can import in Secure Exec, and how each one is backed.","Guest code in Secure Exec runs as Node.js. It never touches the host runtime: every guest `import`/`require` of a `node:` builtin resolves to a kernel-backed bridge or an in-isolate polyfill, never the real host module. This page describes which builtins are available and how each one is implemented.\n\nThe guest reports itself as Node `v22.0.0` (`process.version`).\n\n## How builtins are backed\n\nThere are three ways a builtin is provided to guest code:\n\n- **Bridge.** A kernel-backed implementation. Calls route through the kernel VFS, socket table, process table, DNS resolver, or host entropy. This is how `fs`, `net`, `http`, `child_process`, `dns`, `os`, and `crypto` reach virtualized resources while staying inside the isolation boundary.\n- **Polyfill.** A pure-JavaScript implementation from `node-stdlib-browser` (for example `path`, `events`, `util`, `stream`, `zlib`). These need no host access; they run entirely inside the V8 isolate.\n- **Denied.** The module is intentionally unavailable. Importing it throws an error with code `ERR_ACCESS_DENIED`.\n\nThe canonical inventory lives in `crates/execution/assets/polyfill-registry.json`.\n\n\u003CNote>A guest never falls through to a real host builtin. Anything not bridged or polyfilled is denied, so there is no path where guest code reaches the host runtime.\u003C/Note>\n\n## Bridge-backed builtins\n\nThese route through the kernel and present normal Linux/Node semantics over virtualized resources.\n\n| Module | Backed by |\n| --- | --- |\n| `fs`, `fs/promises` | Kernel VFS. File and directory operations, fds, `createReadStream`/`createWriteStream`, metadata, symlinks. `watch`/`watchFile` are guest-side polling wrappers. |\n| `child_process` | Kernel process table. `spawn`, `exec`, `execFile`, `spawnSync`, `execSync`, `execFileSync` (and the sync variants) run kernel-managed processes. See [Child Processes](/docs/features/child-processes). |\n| `net` | Kernel socket table. TCP client and server sockets, plus Unix sockets. |\n| `dns` | Kernel DNS resolver (`lookup`, `resolve*`, and the `dns/promises` surface). |\n| `http`, `https`, `http2` | Built on the kernel socket path. `request`, `get`, `createServer`, agents with connection pooling. |\n| `tls` | Layered on the kernel `net` polyfill. |\n| `os` | VM-scoped values (platform, arch, hostname, CPU/memory, user info, `os.constants`). |\n| `crypto` | Host entropy and crypto bridges: `getRandomValues`, `randomUUID`, `randomBytes`, `createHash`, `createHmac`, cipher/decipher, scrypt, and `crypto.subtle` (WebCrypto). |\n| `process` | Virtualized `process` global: env (permission-gated), `cwd`/`chdir`, signals, timers, stdio, `umask`. |\n| `module` | `createRequire`, `Module` basics, builtin resolution, `Module.builtinModules`. |\n| `console` | Bridge shim with circular-safe formatting. Output is captured into the `stdout`/`stderr` result fields and can also be streamed via the `onStdout`/`onStderr` hooks on `exec`/`run`/`spawn`. |\n| `dgram` | Kernel socket table (UDP). |\n| `perf_hooks`, `diagnostics_channel`, `async_hooks` | Bridge-backed compatibility surfaces. |\n| `worker_threads` | Compatibility shim: `isMainThread` and inert ports for feature detection. Real worker threads are not spawned. |\n| `vm` | Compatibility shim: `Script`, `createContext`, `isContext`, `runInNewContext`, `runInThisContext`. |\n| `v8` | Compatibility shim for safe inspection/serialization helpers. |\n| `tty` | `isatty` plus `ReadStream`/`WriteStream` compatibility constructors. |\n| `readline`, `sqlite` | Bridge-backed compatibility surfaces. |\n| `timers`, `timers/promises` | `setTimeout`, `setInterval`, `setImmediate`, and promise variants. |\n| `stream/web`, `stream/consumers`, `stream/promises` | Web Streams and stream helper subpaths. |\n\nNetwork builtins (`net`, `dgram`, `dns`, `http`, `https`, `http2`, `tls`) are subject to the per-runtime permission policy, which **denies network access by default**. Operations fail until you opt in. See [Permissions](/docs/features/permissions).\n\n## Polyfilled builtins\n\nPure-JavaScript implementations from `node-stdlib-browser`, running inside the isolate. They support default and named ESM imports.\n\n| Module | Polyfill |\n| --- | --- |\n| `path`, `path/posix`, `path/win32` | `path-browserify` |\n| `buffer` | `buffer` (also re-exports `Blob`/`File`) |\n| `events` | `events` |\n| `stream` | `readable-stream` |\n| `util`, `util/types` | node-stdlib-browser |\n| `assert` | node-stdlib-browser |\n| `url` | node-stdlib-browser shims |\n| `querystring` | node-stdlib-browser |\n| `string_decoder` | node-stdlib-browser |\n| `zlib` | node-stdlib-browser |\n| `punycode` | node-stdlib-browser |\n| `constants` | `constants-browserify` (`os.constants` stays available via `os`) |\n| `console`, `timers` | node-stdlib-browser base, with bridge wiring for stdio and the kernel clock |\n| `sys` | alias of `util` |\n\n## Denied builtins\n\nImporting any of these throws an error with code `ERR_ACCESS_DENIED`:\n\n`cluster`, `domain`, `inspector`, `repl`, `trace_events`, `wasi`.\n\n## Global APIs\n\nWeb platform globals expected by modern npm packages are provided in the isolate, including `fetch`, `Headers`, `Request`, and `Response`. Guest `fetch()` runs through undici inside the V8 isolate and then through the kernel socket table, so it obeys the same network permissions as the `http`/`net` builtins. `TextEncoder`/`TextDecoder`, `Buffer`, `URL`/`URLSearchParams`, `Blob`/`File`, `FormData`, `AbortController`/`AbortSignal`, `structuredClone`, and `performance` are also available.\n\nWebAssembly is enabled inside the isolate (`WebAssembly.Module`, `WebAssembly.Instance`, `WebAssembly.instantiate*`), so packages that ship `.wasm` work. Compilation stays inside the isolate and does not cross the isolation boundary.\n\n## Restricting the builtin surface\n\nThe builtin surface can be narrowed through the [platform / `allowedBuiltins` config](/docs/features/runtime-platform); anything excluded becomes a denied builtin (`ERR_ACCESS_DENIED`).\n\n\u003CWarning>This config (`CreateVmConfig.jsRuntime`) rides the wire `CreateVmConfig` and is not currently exposed through `NodeRuntime.create()`. See [Runtime Platform](/docs/features/runtime-platform) for the platform ladder and [TypeScript SDK](/docs/sdks/typescript) for the config shape.\u003C/Warning>\n\n## Logging behavior\n\n- `console.log`/`warn`/`error` serialize arguments with circular-safe, bounded formatting.\n- `exec()` and `run()` buffer guest output and return it as the `stdout` and `stderr` strings on the result.\n- To observe output incrementally, pass the `onStdout`/`onStderr` hooks, which receive raw `Uint8Array` chunks in emission order; the full strings are still returned when the run ends.\n\nSee [Output Capture](/docs/features/output-capture) for details.\n\n## TypeScript\n\nThe core runtime executes JavaScript. For sandboxed TypeScript usage, see [TypeScript](/docs/features/typescript).\n\n## Example\n\nImport a mix of bridge-backed and polyfilled builtins from guest code:\n\n```ts\nimport { NodeRuntime } from \"secure-exec\";\n\nconst rt = await NodeRuntime.create();\n\ntry {\n const { stdout } = await rt.exec(`\n import path from \"node:path\";\n import { createHash } from \"node:crypto\";\n import { writeFileSync, readFileSync } from \"node:fs\";\n\n const file = path.join(\"/tmp\", \"note.txt\");\n writeFileSync(file, \"hello\");\n\n const digest = createHash(\"sha256\")\n .update(readFileSync(file))\n .digest(\"hex\");\n\n console.log(digest);\n `);\n\n console.log(stdout.trim());\n} finally {\n await rt.dispose();\n}\n```\n\n## See also\n\n- **Module loading and resolution**: how ESM/CJS, the `node_modules` walk, and unmodified npm packages resolve over the virtual filesystem lives in [NPM & Module Loading](/docs/features/module-loading).\n- **Output capture**: how `stdout`/`stderr` are buffered and streamed is documented in [Output Capture](/docs/features/output-capture).","src/content/docs/docs/nodejs-compatibility.mdx","2962184ef084e747","docs/quickstart",{"id":51,"data":53,"body":56,"filePath":57,"digest":58,"deferredRender":19},{"title":54,"description":55},"Quickstart","Get Secure Exec running in a few minutes.","\u003CSteps>\n\n1. **Install**\n\n \u003CCodeGroup>\n ```bash title=\"npm\"\n npm install secure-exec\n ```\n\n ```bash title=\"bun\"\n bun add secure-exec\n ```\n\n ```bash title=\"pnpm\"\n pnpm add secure-exec\n ```\n\n ```bash title=\"yarn\"\n yarn add secure-exec\n ```\n \u003C/CodeGroup>\n\n2. **Create a runtime**\n\n `NodeRuntime.create()` boots a fully virtualized VM behind the native sidecar. Guest code runs inside the kernel isolation boundary with no host escapes. All options are optional: `cwd` defaults to `/workspace`, and permissions default to a secure policy that denies network access (see step 4).\n\n ```ts\n import { NodeRuntime } from \"secure-exec\";\n\n const runtime = await NodeRuntime.create();\n ```\n\n3. **Run code**\n\n Use `run()` when you want a JSON value back; the guest calls `globalThis.__return(value)` to set it. Use `exec()` when you care about side effects and want to capture `stdout`/`stderr`/`exitCode`. Guest code runs as an ES module, so `import` and top-level `await` both work.\n\n \u003CCodeGroup>\n \u003CCodeSnippet file=\"examples/docs/quickstart/src/index.mts\" title=\"Return a value\" />\n\n ```ts title=\"Capture output\"\n import { NodeRuntime } from \"secure-exec\";\n\n const runtime = await NodeRuntime.create();\n\n try {\n // exec() runs guest code for its side effects and captures the streams.\n const result = await runtime.exec(`\n console.log(\"hello from secure-exec\");\n console.error(\"this goes to stderr\");\n `);\n\n console.log(\"stdout:\", JSON.stringify(result.stdout.trim()));\n console.log(\"stderr:\", JSON.stringify(result.stderr.trim()));\n console.log(\"exitCode:\", result.exitCode);\n } finally {\n await runtime.dispose();\n }\n ```\n \u003C/CodeGroup>\n\n *[See Full Example](https://github.com/rivet-dev/secure-exec/tree/main/examples/docs/quickstart)*\n\n4. **Configure permissions (optional)**\n\n Guest code is **deny-by-default** for network access. Pass a `permissions` policy to `NodeRuntime.create()` to opt in; it merges over the secure default, so you only specify what you want to change:\n\n ```ts\n const runtime = await NodeRuntime.create({\n permissions: { network: \"allow\" },\n });\n ```\n\n See [Permissions](/docs/features/permissions) for the full scope list and merge semantics.\n\n\u003C/Steps>\n\n## Next steps\n\n\u003CCardGroup>\n \u003CCard title=\"Crash Course\" href=\"/docs/crash-course\">\n A fast tour of the essential SDK API and core concepts.\n \u003C/Card>\n \u003CCard title=\"Permissions\" href=\"/docs/features/permissions\">\n Control filesystem, network, and process access.\n \u003C/Card>\n\u003C/CardGroup>","src/content/docs/docs/quickstart.mdx","8e3dc2f92c8e2465","docs/security-model",{"id":59,"data":61,"body":64,"filePath":65,"digest":66,"deferredRender":19},{"title":62,"description":63},"Security Model","A short overview of Secure Exec isolation and trust, with a link to the canonical agentOS security model.","Secure Exec runs guest code inside a fully virtualized VM so untrusted code stays contained. At a glance:\n\n- **V8 isolate boundary**: Guest JavaScript runs in a V8 isolate inside the kernel. It never spawns a real host process, touches the real host filesystem, or opens a real host socket.\n- **Sidecar enforces**: A trusted sidecar owns the kernel, VFS, socket table, and permission policy. Every guest syscall is mediated and checked there, not on the host.\n- **Executor is untrusted**: The code you submit for execution is treated as actively hostile. How it reached the executor never makes it trusted.\n- **Secure defaults**: The network is deny-by-default; filesystem, child processes, process info, and env are enabled so normal programs run. Resource and timing limits bound runaway or hostile code.\n\n## Full reference\n\nThe canonical threat model, trust boundaries, and detailed enforcement guarantees are owned by agentOS.\n\n\u003CCard title=\"agentOS: Security Model\" href=\"https://agentos-sdk.dev/docs/security-model\">\n The complete trust model, threat model, and enforcement details.\n\u003C/Card>","src/content/docs/docs/security-model.mdx","e07642db1c564f7b","docs/comparison/cloudflare-workers",{"id":67,"data":69,"body":72,"filePath":73,"digest":74,"deferredRender":19},{"title":70,"description":71},"Secure Exec vs Cloudflare Workers","How Secure Exec and Cloudflare Workers differ in isolation model, permissions, networking, and Node.js compatibility.","Secure Exec and Cloudflare Workers both run untrusted JavaScript inside V8, but they solve different problems. Workers is a managed, multi-tenant edge platform: you deploy code and Cloudflare runs it for you across its network. Secure Exec is a library you embed in your own application to run guest code locally inside a fully virtualized VM that you control. This page focuses on how the two differ in isolation, permissions, networking, and Node.js surface.\n\n## At a glance\n\n| | Secure Exec | Cloudflare Workers |\n| --- | --- | --- |\n| **Form factor** | Library you embed (`secure-exec`), runs where your app runs | Managed edge platform you deploy to |\n| **Isolation unit** | Per runtime: each `NodeRuntime.create()` is its own VM and OS process | Per Worker isolate, scheduled by Cloudflare |\n| **Guest runtime** | V8 isolate inside a virtualized POSIX kernel (filesystem, processes, sockets, PTYs) | V8 isolate with the `workerd` runtime |\n| **Permissions** | Deny-by-default capability policy you configure per runtime | Platform-managed; no per-call capability policy |\n| **Subprocesses** | Real `node:child_process` against kernel-managed processes | Not available |\n| **Filesystem** | Full virtualized filesystem per runtime | Limited in-memory `node:fs` surface, ephemeral |\n| **You operate it** | Yes (your process, your machine) | No (Cloudflare operates it) |\n\n## Isolation model\n\nThis is the most important difference, and the easiest one to misstate.\n\nCloudflare Workers isolates code dynamically. Cloudflare's runtime schedules many Workers into a pool of V8 isolates and can move work between them, with platform-level mitigations (such as I/O-gated clock coarsening) layered on to defend against side-channel attacks across that shared infrastructure.\n\nSecure Exec isolates code statically, one boundary per runtime. Every `NodeRuntime.create()` boots a fully virtualized VM backed by its own sidecar process. Two runtimes share nothing: not the filesystem, not globals, not module state, and not crash fate. Secure Exec does not reassign guest code between processes at runtime, and it does not claim Cloudflare-style dynamic, cross-tenant isolate scheduling. You decide the blast radius by deciding how many runtimes to create and what to put in each one.\n\nWithin a single runtime, every `exec()` or `run()` call runs in a fresh guest process, so in-memory state from one run does not leak into the next.\n\n\u003CCard title=\"Process Isolation\" href=\"/docs/architecture\">\n\tHow runtimes and runs are isolated, and how to choose granularity.\n\u003C/Card>\n\nThe practical consequence: with Workers you trust Cloudflare's platform to keep tenants apart. With Secure Exec you get a hard, statically-defined boundary per runtime that you place yourself, which is well suited to running one tenant or one task per runtime and disposing it when finished.\n\n## Permissions\n\nCloudflare Workers does not expose a per-invocation capability policy. What a Worker can reach is governed by its bindings and platform configuration.\n\nSecure Exec applies a deny-by-default capability policy per runtime. Network access is denied until you opt in; the virtualized filesystem, child-process, process, and env scopes are enabled so programs can run at all (the guest only ever sees the VM, never the real host). You tighten or widen any scope when you create the runtime.\n\n```ts\nimport { NodeRuntime } from \"secure-exec\";\n\n// Default: no network access. Filesystem and processes are virtualized.\nconst sandboxed = await NodeRuntime.create();\n\n// Opt into network access while keeping the other defaults.\nconst networked = await NodeRuntime.create({\n permissions: { network: \"allow\" },\n});\n```\n\n\u003CNote>The permission policy is merged over a secure default, so a partial policy like `{ network: \"allow\" }` works. See [Permissions](/docs/features/permissions) for rule-set syntax to gate individual scopes.\u003C/Note>\n\n## Networking\n\nInside the VM, guest `fetch()` runs through undici in the V8 isolate and then through the kernel's socket table, gated by the network permission. Guest code can also bind ports inside the VM: Secure Exec exposes `findListener()` and `waitForListener()` so the host can detect when a guest process starts listening (for example, to wait for an in-VM HTTP server before sending it a request).\n\nFrom the host side, `rt.fetch(port, input)` drives an HTTP request into a guest server listening inside the VM and reads the response back. The request never leaves the VM (it connects to the guest's loopback listener through the kernel socket table), so it works even when guest network egress is denied.\n\nCloudflare Workers provides outbound `fetch()` and a Sockets API for outbound TCP/TLS, but a Worker does not listen on a port the way a normal server does; it responds to incoming requests routed by the platform.\n\n```ts\nimport { NodeRuntime } from \"secure-exec\";\n\nconst rt = await NodeRuntime.create();\ntry {\n // Start a long-running guest HTTP server and get a live handle back.\n const server = await rt.spawn(`\n import http from \"node:http\";\n http.createServer((_req, res) => res.end(\"ok\")).listen(3000);\n `);\n\n // Block until the listener is up, then drive a request into it from the host.\n await rt.waitForListener({ port: 3000 });\n const res = await rt.fetch(3000, { path: \"/\" });\n console.log(res.status, res.body); // 200 ok\n\n server.kill();\n await server.wait();\n} finally {\n await rt.dispose();\n}\n```\n\n## Subprocesses and the POSIX surface\n\nSecure Exec presents a virtualized POSIX environment. Guest code can use `node:child_process` to spawn commands that exist inside the VM (such as `sh` and the mounted coreutils), and every child is a kernel-managed process, never a real host process. The host can also start a long-running guest program and drive it with `rt.spawn()`.\n\nCloudflare Workers has no subprocess model. There is no `child_process`, no process table, and no shell.\n\n\u003CCard title=\"Child Processes\" href=\"/docs/features/child-processes\">\n\tSpawn kernel-managed processes from guest code, or drive a long-running guest program from the host.\n\u003C/Card>\n\n## Node.js compatibility\n\nBoth runtimes aim to present Node.js semantics on top of V8, and both implement a large subset of the Node.js standard library. The character of the gaps differs:\n\n- **Secure Exec** is backed by a real virtualized kernel, so capabilities that need an OS, a full filesystem, real child processes, sockets that listen, and a process table, are first-class. Pure-JS builtins are provided through `node-stdlib-browser`, and kernel-backed modules (such as `fs`, `net`, `child_process`, `dns`, `http`, `os`) are wired through the bridge to the kernel.\n- **Cloudflare Workers** provides Node.js compatibility through the `nodejs_compat` flag on top of `workerd`. Its filesystem is a limited in-memory surface, there is no subprocess support, and listening servers are replaced by the request/response handler model. In exchange it ships a comprehensive native `node:crypto` and Web Crypto surface and platform-native logging.\n\n\u003CNote>Module support evolves on both sides. Treat the points above as the shape of the difference (kernel-backed POSIX vs managed edge isolate), not a frozen feature matrix. Verify a specific module against the current behavior of whichever runtime you target.\u003C/Note>\n\n## When to choose which\n\nChoose **Cloudflare Workers** when you want a managed, globally distributed platform to deploy your own trusted code to, with the operations handled for you.\n\nChoose **Secure Exec** when you need to run untrusted or AI-generated code inside your own application with a hard, self-placed isolation boundary, a real virtualized filesystem and process model, and a capability policy you control. One runtime per tenant or per task gives you a clean blast radius you can dispose on demand.\n\n\u003CCard title=\"Process Isolation\" href=\"/docs/architecture\">\n\tThe isolation model in depth, plus how to pick isolation granularity.\n\u003C/Card>","src/content/docs/docs/comparison/cloudflare-workers.mdx","5d8381fa131cea20","docs/comparison/isolated-vm",{"id":75,"data":77,"body":80,"filePath":81,"digest":82,"deferredRender":19},{"title":78,"description":79},"Secure Exec vs isolated-vm","How Secure Exec and isolated-vm differ in isolation surface, security confinement, performance, and developer experience.","Both Secure Exec and isolated-vm run untrusted JavaScript inside V8 isolates, but they operate at different layers. isolated-vm is a low-level npm library that exposes a bare V8 isolate with manual value marshaling and no system surface. Secure Exec wraps V8 isolates in a full virtualized kernel: a POSIX-like VFS, process table, socket table, permission policy, and resource limits. This page focuses on the security and performance characteristics of that core runtime layer.\n\n## At a glance\n\n| | Secure Exec | isolated-vm |\n| --- | --- | --- |\n| **Layer** | Full virtualized runtime around V8 isolates | Bare V8 isolate primitive |\n| **System surface** | Virtualized filesystem, processes, sockets, PTYs, DNS | None (you build any surface yourself) |\n| **Host and guest data** | Normal Node/POSIX I/O through the kernel | Manual `Reference`/`Copy`/`ExternalCopy` marshaling |\n| **Permission model** | Deny-by-default capability policy per runtime | None (whatever you expose is reachable) |\n| **Network egress** | Mediated by the kernel socket table, gated by policy | None by default; any bridge you add is unmediated |\n| **Resource limits** | Per-VM CPU, memory, and other caps | Memory limit and timeout per isolate |\n| **npm / Node compat** | Real npm packages run unmodified | None (no module system, no `node:` builtins) |\n\n## Isolation boundary\n\nThe core difference is how much exists inside the boundary.\n\n- **isolated-vm** gives you a raw V8 isolate and nothing else. There is no filesystem, no network, no process model, and no globals beyond the ECMAScript spec. Anything the guest can reach, you have to inject yourself across the host/guest boundary by hand.\n- **Secure Exec** boots a fully virtualized VM per runtime. The guest sees a POSIX-like filesystem, a process table, sockets, pipes, PTYs, and DNS, all backed by a kernel that the guest can never escape. Every guest syscall is routed through kernel-owned paths.\n\nThe trade-off: isolated-vm is a primitive you assemble a sandbox out of. Secure Exec is the assembled sandbox.\n\n## Security\n\nA bare V8 isolate confines memory and CPU, but it confines nothing else, because there is nothing else inside it. The security of an isolated-vm deployment is entirely a property of the bridge code you write around it.\n\n- **What isolated-vm confines**: heap memory (per-isolate limit) and execution time (per-call timeout). It cannot leak host memory directly because the guest has no references it was not given.\n- **What you must build yourself**: every capability the guest needs (file access, network, subprocesses) is a function you expose across the boundary. Each exposed function is attack surface, and each is unmediated unless you add your own checks.\n- **What Secure Exec confines**: in addition to memory and time, it enforces a deny-by-default capability policy over filesystem, network, child-process, process, and env scopes. A denied operation fails with `EACCES`.\n- **Egress control**: guest `fetch()`, `node:http`, and raw sockets flow through the kernel socket table, so outbound traffic can be allowed, denied, or rule-matched. With isolated-vm there is no networking until you build it, and once built it is not policed.\n\n\u003CNote>With isolated-vm, a mistake in your marshaling layer (handing the guest a live host `Reference`, or an injected function that does unchecked I/O) is a sandbox escape. Secure Exec moves that boundary into a kernel so the surface the guest sees is virtualized rather than hand-wired per project.\u003C/Note>\n\n```ts\nimport { NodeRuntime } from \"secure-exec\";\n\n// Deny-by-default: no network, filesystem and processes are virtualized.\nconst rt = await NodeRuntime.create();\n\n// Opt into network egress; it is still mediated by the kernel socket table.\nconst networked = await NodeRuntime.create({\n permissions: { network: \"allow\" },\n});\n```\n\n\u003CCard title=\"Permissions\" href=\"/docs/features/permissions\">\n\tThe deny-by-default capability policy and per-scope rule sets.\n\u003C/Card>\n\n## Performance\n\nBoth runtimes execute guest code in a V8 isolate, so raw JavaScript throughput is comparable. The cost differences come from what surrounds the isolate.\n\n- **isolated-vm** is the thinner layer: creating an isolate is cheap, and the dominant per-call cost is marshaling values across the host/guest boundary, which is explicit and pay-as-you-go.\n- **Secure Exec** adds syscall virtualization. Guest I/O (files, sockets, processes) is routed through the kernel, so operations that touch the system carry virtualization overhead that a bare isolate does not. Pure compute that never makes a syscall runs at isolate speed.\n- **Startup**: Secure Exec boots a virtualized VM per runtime, which is heavier than spinning up a bare isolate, but it is far lighter than a container or microVM. Reusing a live guest process drives warm execution into the low-millisecond range. See [Benchmarks](/docs/benchmarks) for measured numbers.\n\nThe summary: isolated-vm has lower overhead because it does less; Secure Exec spends that overhead on a real system surface and enforcement you would otherwise build and pay for yourself.\n\n## Developer experience\n\nThis is where the two diverge most for everyday use.\n\n- **isolated-vm**: you write to the isolate API directly. There is no module loader, no `node:` builtins, and no normal I/O. Passing data in or out means `Reference`, `Copy`, or `ExternalCopy`, and any capability is a function you wrap and inject. Running an existing npm package is not a goal of the library.\n- **Secure Exec**: the guest sees normal Linux and Node semantics. Real npm packages run unmodified, resolved over a faithfully mounted `node_modules`, and kernel-backed modules (`fs`, `net`, `child_process`, `dns`, `http`, `os`) work as they would on a real machine.\n\n```ts\nimport { NodeRuntime } from \"secure-exec\";\n\nconst rt = await NodeRuntime.create();\ntry {\n const result = await rt.run\u003Cnumber>(`\n __return(40 + 2);\n `);\n console.log(result.value); // 42\n} finally {\n await rt.dispose();\n}\n```\n\n## When to choose which\n\n| Choose | When |\n| --- | --- |\n| **isolated-vm** | You want a minimal V8 isolate primitive and intend to design and own the entire sandbox surface, capability injection, and enforcement yourself. |\n| **Secure Exec** | You want to run untrusted or AI-generated code with a virtualized filesystem, process model, and networking, plus a deny-by-default permission policy and resource limits, without hand-building the sandbox. |\n\n\u003CCard title=\"Process Isolation\" href=\"/docs/architecture\">\n\tThe isolation model in depth, plus how to pick isolation granularity.\n\u003C/Card>","src/content/docs/docs/comparison/isolated-vm.mdx","3b4524d0b760f759","docs/comparison/quickjs",{"id":83,"data":85,"body":88,"filePath":89,"digest":90,"deferredRender":19},{"title":86,"description":87},"Secure Exec vs QuickJS","How Secure Exec and QuickJS differ in isolation model, performance, language coverage, and system surface.","Secure Exec and QuickJS both run guest JavaScript, but they sit at different layers. QuickJS is a small, embeddable JavaScript engine: you link it into a host process and call its C API. Secure Exec is a full virtualized runtime built on V8, with a kernel, virtual filesystem, and capability policy around the engine. This page focuses on the security and performance characteristics of the core runtime layer.\n\n## At a glance\n\n| | Secure Exec | QuickJS |\n| --- | --- | --- |\n| **Engine** | V8 isolate (JIT) | QuickJS bytecode interpreter |\n| **Isolation** | Virtualized VM in a dedicated sidecar process | Interpreter embedded in your host process |\n| **Performance** | JIT-compiled, high throughput | Interpreted, smaller working set |\n| **Language** | Full modern ECMAScript | Mostly ES2023, smaller engine |\n| **Node/npm** | Real npm packages and Node-compatible builtins | None built in |\n| **System surface** | Kernel: filesystem, processes, sockets, PTYs | None (host C bindings only) |\n\n## Isolation model\n\nThis is the most important difference.\n\n- **QuickJS** is an interpreter you embed directly in your host process. Guest code shares the host's address space, and anything the guest can reach is whatever your C bindings expose. There is no process boundary between guest and host by default, so isolation is entirely your responsibility to build and audit.\n- **Secure Exec** runs guest code in a V8 isolate inside a separate sidecar process, behind a virtualized POSIX kernel. Guest code never calls real Node.js builtins, never opens a real host socket, and never touches the real disk. Every syscall is routed through the kernel and checked against a deny-by-default permission policy.\n\nThe practical consequence: with QuickJS you own the entire sandbox, including the boundary, the permission checks, and the host-bindings audit surface. With Secure Exec the boundary, the kernel, and the policy enforcement are provided and run out-of-process.\n\n\u003CCard title=\"Process Isolation\" href=\"/docs/architecture\">\n\tHow runtimes and runs are isolated, and how to choose granularity.\n\u003C/Card>\n\n## Performance\n\nThe engines optimize for different things.\n\n- **V8 (Secure Exec)** JIT-compiles hot code to native machine code, so sustained throughput on compute-heavy guest code is far higher. The trade-off is a larger engine and a heavier per-isolate baseline.\n- **QuickJS** compiles to bytecode and interprets it. It has a very small footprint and fast startup for a single embedded instance, but interpreted execution is slower on throughput-bound work.\n\nFor Secure Exec, cold start is dominated by bringing up the guest runtime rather than provisioning infrastructure, and reusing a live guest process drives warm execution into the low-millisecond range.\n\n\u003CNote>Treat these as the shape of the difference (JIT throughput vs interpreter footprint), not fixed numbers. See [Benchmarks](/docs/benchmarks) for measured cold-start, warm, and reuse numbers and the methodology behind them.\u003C/Note>\n\n## Language and ecosystem coverage\n\n- **Secure Exec** runs full modern ECMAScript on V8, the same engine as Node.js and Chrome, so language features land as V8 ships them. Real npm packages run unmodified inside the VM, resolved over a faithfully mounted `node_modules` like a real filesystem, and Node-compatible builtins are wired through the kernel.\n- **QuickJS** implements most of the ECMAScript specification in a compact engine, but it tracks the spec on its own cadence and lags V8 on newer features and edge cases. It ships no Node.js standard library and no npm resolution; any package or builtin support is something you bind in yourself.\n\n## System surface\n\n- **Secure Exec** presents a virtualized POSIX environment to guest code: a per-runtime virtual filesystem, a kernel-managed process table (with `node:child_process`), a socket table for networking, pipes, and PTYs. Guest `fetch()`, `node:http`, and raw sockets all flow through the kernel and the permission policy.\n- **QuickJS** has none of this built in. The bare engine exposes only ECMAScript globals; there is no filesystem, no process model, no networking, and no shell unless your host code adds C bindings for them. Every capability the guest needs is host surface you write and must secure.\n\n\u003CCard title=\"Child Processes\" href=\"/docs/features/child-processes\">\n\tSpawn kernel-managed processes from guest code, or drive a long-running guest program from the host.\n\u003C/Card>\n\n## When to choose which\n\nChoose **QuickJS** when you need the smallest possible embeddable engine, you are running short, self-contained scripts with no system needs, and you are prepared to build and audit any sandbox boundary and host bindings yourself.\n\nChoose **Secure Exec** when you need full ECMAScript and npm compatibility, JIT throughput, and a ready-made isolation boundary with a kernel-backed filesystem, process model, networking, and a deny-by-default capability policy you control.\n\n\u003CCard title=\"Process Isolation\" href=\"/docs/architecture\">\n\tThe isolation model in depth, plus how to pick isolation granularity.\n\u003C/Card>","src/content/docs/docs/comparison/quickjs.mdx","83af8c4fd3956377","docs/comparison/sandbox",{"id":91,"data":93,"body":96,"filePath":97,"digest":98,"deferredRender":19},{"title":94,"description":95},"Secure Exec vs Container Sandbox","When to use a container sandbox versus Secure Exec for running untrusted code.","Secure Exec and container sandboxes both run untrusted code in isolation, but they sit at different points on the weight-versus-flexibility curve. Picking the right one depends on what you need to run.\n\n**Secure Exec** boots a fully virtualized VM for each runtime and runs guest JavaScript in a V8 isolate inside a dedicated sidecar process. There is no Docker daemon, no orchestrator, and no vendor account: you `npm install` the package and call `NodeRuntime.create()`. It is built for lightweight, high-fanout code execution like AI tool calls, user scripts, and plugins, where you want granular permissions and a small footprint.\n\n**Container sandboxes** (e2b, Daytona, Modal, Cloudflare Containers, and similar) spin up a full OS image with system packages, a writable disk, and the ability to run arbitrary binaries. They are built for heavyweight workloads that need a complete environment: coding agents, long-lived dev sessions, or anything that shells out to native tools.\n\n## How isolation works\n\nThe biggest difference is what the isolation boundary is made of.\n\n- **Secure Exec** runs guest code in a V8 isolate hosted by its own sidecar process. Every `NodeRuntime.create()` is a separate VM with its own virtual filesystem, process table, network policy, and crash domain. Guest code never calls real Node.js builtins, never opens a real host socket, and never touches the real disk. Every syscall is routed through the kernel. See [Process Isolation](/docs/architecture).\n- **Container sandboxes** isolate with OS-level primitives (namespaces, cgroups, or a microVM). The guest runs a real kernel and a real filesystem, so it can do anything a Linux process can, constrained by the container's configuration.\n\nSecure Exec presents normal Linux semantics to the code it runs (a POSIX-like virtual filesystem, processes, pipes, PTYs, sockets) without granting access to the host that backs them.\n\n## Comparison\n\n| Dimension | Secure Exec | Container Sandbox |\n| --- | --- | --- |\n| Isolation boundary | Virtualized VM + V8 isolate in a sidecar process | OS container or microVM |\n| Setup | `npm install secure-exec` | Vendor account or Docker host |\n| Hardware | Runs on your infrastructure | Often vendor-hosted |\n| Filesystem | Virtual, in-memory, per runtime | Full OS filesystem |\n| Network | Denied by default, opt-in per runtime | Full, or firewall rules |\n| Permissions | Per-scope policy (fs, network, childProcess, process, env, tool) | Coarse, container-level |\n| Languages | JavaScript and TypeScript (Node-compatible) | Any language the image supports |\n| Arbitrary binaries | No (guest binaries run through the VM, not the host) | Yes |\n| Crash domain | One process per runtime | One container per sandbox |\n\n## What Secure Exec gives you\n\nThese capabilities are the reason to reach for Secure Exec over a container when the workload fits in a Node-compatible runtime:\n\n- **Deny-by-default permissions.** Network egress is blocked until you opt in, and every guest syscall is checked against a per-scope policy before any host resource is touched. A denied operation fails with `EACCES`. See [Permissions](/docs/features/permissions).\n- **Virtual filesystem.** Each runtime gets its own in-memory filesystem. Guest reads and writes never reach the host disk, and two runtimes writing the same path do not collide. See [Filesystem](/docs/features/filesystem).\n- **Mediated networking.** Guest `fetch()`, `node:http`, and raw sockets all flow through the kernel socket table, so you can allow, deny, or rule-match outbound traffic. See [Networking](/docs/features/networking).\n- **Process-level isolation.** Each runtime is its own VM and its own crash domain, and each `exec()` / `run()` starts a fresh guest process so in-memory state never leaks between runs. See [Process Isolation](/docs/architecture).\n- **npm compatibility.** Real npm packages run unmodified inside the VM, resolved over a faithfully mounted `node_modules` like a real filesystem. See [Module Loading](/docs/features/module-loading).\n\n## When to use each\n\n### Use Secure Exec when\n\n- You are running **JavaScript or TypeScript** (AI tool calls, user scripts, plugins, evaluation loops).\n- You want **no vendor dependency** and to run on your own infrastructure.\n- You need **granular, deny-by-default permissions** over the filesystem, network, and child processes.\n- You are running **many short tasks** and want a small per-task footprint.\n\n### Use a container sandbox when\n\n- You need a **full OS environment**: system packages, arbitrary binaries, or languages beyond a Node-compatible runtime.\n- You need a **persistent, long-lived** environment such as a multi-hour dev session.\n- The workload genuinely needs a real kernel and a real disk.\n\n\u003CNote>\n**Need a full sandboxed operating system?**\n\nIf your workload needs complete sandbox environments (for example, running coding agents like Claude Code, Codex, or Amp), the [Sandbox Agent SDK](https://sandboxagent.dev/) provides a unified interface for driving agents inside sandboxes.\n\u003C/Note>\n\n## A minimal example\n\nBooting a Secure Exec runtime takes no infrastructure beyond the installed package. The runtime owns its VM until you dispose it:\n\n```ts\nimport { NodeRuntime } from \"secure-exec\";\n\n// Network is denied by default; the guest runs in its own virtualized VM.\nconst rt = await NodeRuntime.create();\ntry {\n const result = await rt.run\u003Cnumber>(`\n __return(40 + 2);\n `);\n console.log(result.value); // 42\n} finally {\n await rt.dispose();\n}\n```\n\nThere is no container to build, no image to pull, and no daemon to keep running.\n\n## Performance\n\nBecause there is no container image or microVM to boot, a Secure Exec runtime starts in a fraction of the time a container takes, and the dominant cost is bringing up the guest runtime rather than provisioning infrastructure. For workloads that run the same kind of snippet repeatedly, reusing a live guest process drives warm execution into the low-millisecond range. See [Benchmarks](/docs/benchmarks) for measured cold-start, warm, and reuse numbers and the methodology behind them.","src/content/docs/docs/comparison/sandbox.mdx","3414ed162e592f0f","docs/features/bindings",{"id":99,"data":101,"body":104,"filePath":105,"digest":106,"deferredRender":19},{"title":102,"description":103},"Bindings","Give sandboxed guest code a narrow, curated set of host-backed capabilities.","Bindings are host-side functions the guest invokes by name:\n\n- **Where the handler runs**: on the **host**, never inside the guest sandbox.\n- **Return value**: round-trips back to the guest as JSON.\n- **Why use them**: hand untrusted guest code a narrow, curated capability surface (the kind an AI agent calls as tools) without granting it the underlying access.\n\n## Registering tools at boot\n\nPass `tools` to `NodeRuntime.create()`. Each key becomes a named command the guest can run.\n\n```ts\nimport { NodeRuntime } from \"secure-exec\";\n\nconst rt = await NodeRuntime.create({\n tools: {\n \"get-weather\": {\n description: \"Look up the current temperature for a city\",\n inputSchema: {\n type: \"object\",\n properties: { city: { type: \"string\" } },\n required: [\"city\"],\n },\n // Runs on the HOST. The return value is delivered back to the guest.\n handler: ({ city }: { city: string }) => {\n const table: Record\u003Cstring, { temp_f: number }> = {\n \"San Francisco\": { temp_f: 61 },\n Tokyo: { temp_f: 75 },\n };\n return table[city] ?? { temp_f: null };\n },\n },\n },\n});\n```\n\n*[See Full Example](https://github.com/rivet-dev/secure-exec/tree/main/examples/docs/uc-code-mode)*\n\n## Registering tools on a live runtime\n\nYou can also add tools after the VM is running with `rt.registerTools({...})`. This is the same capability as the `tools` create option, exposed for a running runtime.\n\n```ts\nawait rt.registerTools({\n reverse: {\n description: \"Reverse a string\",\n inputSchema: {\n type: \"object\",\n properties: { text: { type: \"string\" } },\n required: [\"text\"],\n },\n handler: ({ text }: { text: string }) => ({ result: [...text].reverse().join(\"\") }),\n },\n});\n```\n\nWhen you register tools on a live runtime, make sure the `tool` permission scope is granted (see below) so the tools are invocable.\n\n## The tool definition\n\nA `HostToolDefinition` has these fields:\n\n- **`description`** (required): human-readable summary of what the tool does.\n- **`inputSchema`** (required): JSON Schema describing the input.\n- **`handler(input)`** (required): the function that runs on the host, returning a JSON-serializable value.\n- **`timeoutMs`** (optional): abort the host handler after this many milliseconds.\n- **`examples`** (optional): worked examples (each `{ description, input }`) shown alongside the tool.\n- **`commandAliases`** (optional): extra command names the guest may use, beyond the registered key.\n\n```ts\nconst rt = await NodeRuntime.create({\n tools: {\n lookupWeather: {\n description: \"Look up the current weather for a city\",\n inputSchema: {\n type: \"object\",\n properties: { city: { type: \"string\" } },\n required: [\"city\"],\n },\n timeoutMs: 5000,\n examples: [{ description: \"Weather in Tokyo\", input: { city: \"Tokyo\" } }],\n commandAliases: [\"weather\"],\n handler: async ({ city }: { city: string }) => {\n // Real host access lives here, behind the tool boundary. The guest\n // never gets the network credential, only the curated result.\n const res = await fetch(`https://example.com/weather?city=${city}`);\n return await res.json();\n },\n },\n },\n});\n```\n\nThe full type shape is in the [TypeScript SDK reference](/docs/sdks/typescript).\n\n## Invoking a tool from the guest\n\nGuest code calls a tool with the `callHostTool(name, input)` global. It returns a promise that resolves with the host handler's JSON result:\n\n```ts\nawait rt.exec(`\n const { temp_f } = await callHostTool(\"get-weather\", { city: \"Tokyo\" });\n console.log(temp_f); // 75\n`);\n```\n\n`callHostTool` is available in every guest program run through `exec`, `run`, and `spawn`. A `commandAlias` (for example `weather` above) works in place of the registered key.\n\nUnder the hood, a registered tool is exposed two ways:\n\n- **As a `PATH` command**: resolved as `/usr/bin/\u003Cname>` inside the VM, so the same invocation can be driven directly through `node:child_process` if you prefer.\n- **Via `callHostTool`**: a thin wrapper over exactly that command path, so both share the same permission and validation behavior.\n\n```ts\nawait rt.exec(`\n import { execFileSync } from \"node:child_process\";\n\n const input = { city: \"Tokyo\" };\n // argv[0] is the command name, then --json and the JSON-encoded input.\n const out = execFileSync(\"get-weather\", [\"get-weather\", \"--json\", JSON.stringify(input)]);\n // The raw command writes a { ok, result } envelope; the handler's return\n // value is under \"result\". callHostTool unwraps this for you.\n const { ok, result } = JSON.parse(out.toString());\n console.log(result.temp_f); // 75\n`);\n```\n\n## The `tool` permission scope\n\nTool invocation is gated by the `tool` permission scope.\n\n- When you pass `tools` to `create()` and set **no** `tool` policy, the `tool` scope is auto-granted so your tools are invocable out of the box.\n- Otherwise grant it explicitly so tools can run:\n\n```ts\nconst rt = await NodeRuntime.create({\n tools: { /* ... */ },\n permissions: { tool: \"allow\" },\n});\n```\n\nUse a rule set instead of `\"allow\"` for per-tool gating, allowing some tool names while denying others. See [Permissions](/docs/features/permissions) for rule-set semantics.\n\n## Wiring a tool into an LLM agent\n\nBindings pair naturally with an LLM agent: expose a sandbox capability to the model as a tool and let the model drive it through its own tool-calling loop.\n\nThe example below uses the Vercel AI SDK to give the model a `runJs` tool whose `execute` runs guest code inside the runtime. The model-generated code is untrusted input, but it executes only inside the VM under the secure-default policy (network denied here), so the model can experiment freely without reaching the host.\n\n```ts\nimport { NodeRuntime } from \"secure-exec\";\nimport { generateText, tool } from \"ai\";\nimport { openai } from \"@ai-sdk/openai\";\nimport { z } from \"zod\";\n\nconst rt = await NodeRuntime.create({ permissions: { network: \"deny\" } });\n\nawait generateText({\n model: openai(\"gpt-4o\"),\n prompt: \"Compute the 10th Fibonacci number by writing JavaScript.\",\n tools: {\n runJs: tool({\n description: \"Run JavaScript inside the sandbox and capture its output.\",\n inputSchema: z.object({ code: z.string() }),\n execute: async ({ code }) => {\n const result = await rt.exec(code);\n return { stdout: result.stdout, stderr: result.stderr };\n },\n }),\n },\n});\n```","src/content/docs/docs/features/bindings.mdx","88313ae73ad96967","docs/features/child-processes",{"id":107,"data":109,"body":112,"filePath":113,"digest":114,"deferredRender":19},{"title":110,"description":111},"Child Processes","Spawn child processes from sandboxed code.","Two ways to run processes in Secure Exec:\n\n- **Guest `node:child_process`**: guest code spawns commands inside the VM. Every child is a kernel-managed process, never a real host process.\n- **`rt.spawn(code)`**: the host starts a long-running guest program and gets a live handle (`pid`, `writeStdin`, `kill`, `wait`, `exitCode`).\n\n## Guest child_process\n\nGuest code uses the standard `node:child_process` module to spawn commands available in the VM (`sh`, `node`, and the mounted coreutils):\n\n\u003CCodeSnippet file=\"examples/docs/feat-child-processes/src/index.mts\" />\n\nOutput:\n\n```\nexitCode: 0\nguest stdout:\nsh output: hello from a child process\nchild node version: v22.0.0\n```\n\n- `execFileSync` is used for brevity; the async/streaming APIs (`spawn`, `exec`, `execFile`) also work for incremental stdout/stderr or writing to a child's stdin.\n- Children run any command provided by the mounted runtimes. By default that is WASM-backed `sh` + coreutils and V8-backed `node`.\n- Point at a different set of WASM command binaries with `commandsDir`:\n\n```ts\nconst rt = await NodeRuntime.create({\n commandsDir: \"/path/to/wasm/commands\",\n});\n```\n\n\u003CNote>Child processes always run inside the kernel. Guest code cannot reach a real host process or host binary; `node:child_process` only sees the commands the VM mounts.\u003C/Note>\n\n### Where the commands come from\n\nThe guest `sh` and the coreutils it drives ship as WASM binaries. The kernel cannot spawn any guest process without them, so they are mounted through the WASM runtime at boot. This is how `node:child_process` and the shell work inside the VM with no host processes ever involved.\n\nThe `commandsDir` create option overrides where those WASM command binaries are loaded from. When unset, the runtime resolves a directory using the first match in this order:\n\n1. an explicit `commandsDir` option,\n2. the `SECURE_EXEC_WASM_COMMANDS_DIR` environment variable,\n3. the in-repo build output (`registry/native/target/wasm32-wasip1/release/commands`), present only in developer checkouts,\n4. the commands vendored into the installed `@secure-exec/core` package (published installs).\n\nThe in-repo build output wins over the bundled copy so local edits are picked up without re-vendoring; a fresh `npm install` has no in-repo path and falls through to the vendored commands. See the [TypeScript SDK reference](/docs/sdks/typescript) for the full create-option shape.\n\n## Long-running guests with rt.spawn\n\n`rt.exec` runs to completion and returns captured output. `rt.spawn(code)` returns a live handle immediately while the guest keeps running. It is the building block for dev servers and other long-lived guests.\n\n```ts\nconst proc = await rt.spawn(`\n process.stdin.on(\"data\", (chunk) => {\n process.stdout.write(\"got: \" + chunk.toString());\n });\n`);\n\nproc.writeStdin(\"hello\\n\"); // feed stdin\nproc.closeStdin(); // signal end-of-input\n\nconst exitCode = await proc.wait();\nconsole.log(proc.pid, exitCode);\n```\n\nSee the [TypeScript SDK reference](/docs/sdks/typescript) for the full `NodeRuntimeProcess` and `NodeRuntimeSpawnOptions` shapes. Stream output by passing `onStdout` / `onStderr`, which receive raw `Uint8Array` chunks:\n\n```ts\nconst proc = await rt.spawn(\"setInterval(() => console.log('tick'), 100)\", {\n onStdout: (chunk) => process.stdout.write(new TextDecoder().decode(chunk)),\n});\n// ... later\nproc.kill(); // SIGTERM\nawait proc.wait();\n```\n\n### Driving a guest server\n\nSpawn a server, wait for it to listen, then drive requests into it with `rt.fetch`, entirely inside the VM, even when guest network egress is denied:\n\n```ts\nconst server = await rt.spawn(`\n import http from \"node:http\";\n http.createServer((_, res) => res.end(\"ok\")).listen(3000);\n`);\n\nconst listener = await rt.waitForListener({ port: 3000 });\nconst res = await rt.fetch(listener.port ?? 3000, { path: \"/\" });\nconsole.log(res.status, res.body); // 200 ok\n\nserver.kill();\nawait server.wait();\n```\n\n## Underlying process model\n\n- The kernel process table, signals, and shell that back `node:child_process` and `rt.spawn` are documented in agentOS: [Processes & Shell](https://agentos-sdk.dev/docs/processes).","src/content/docs/docs/features/child-processes.mdx","03c8e309f5394326","docs/features/executing-code",{"id":115,"data":117,"body":120,"filePath":121,"digest":122,"deferredRender":19},{"title":118,"description":119},"Executing Code","Run guest JavaScript with exec() and run(), and return values from the sandbox.","`exec()` and `run()` are the two ways to run guest code to completion. The code\nruns inside the VM as a standard ES module, so top-level `import` and top-level\n`await` both work.\n\n## Run code and capture output\n\n`exec()` runs the code and resolves with `stdout`, `stderr`, and `exitCode`.\n\n```ts\nimport { NodeRuntime } from \"secure-exec\";\n\nconst rt = await NodeRuntime.create();\nconst { stdout, exitCode } = await rt.exec(`\n import os from \"node:os\";\n console.log(\"platform:\", os.platform());\n`);\nconsole.log(stdout, exitCode);\nawait rt.dispose();\n```\n\n## Return a value from the guest\n\n`run\u003CT>()` does everything `exec()` does and also decodes a JSON-serializable\nvalue the guest hands back with the injected `globalThis.__return(value)`. If the\nguest never calls it, `value` is `undefined`.\n\n```ts\nconst { value } = await rt.run\u003C{ sum: number }>(`\n globalThis.__return({ sum: 2 + 40 });\n`);\nconsole.log(value?.sum); // 42\n```\n\n## Per-run options\n\n`exec()` and `run()` take the same per-call options: `stdin` to pipe input, `env`\nand `cwd` to override the environment for one run, a `timeout` and an\n`AbortSignal` to bound it, and `onStdout` / `onStderr` to stream output as it is\nproduced.\n\n```ts\nconst result = await rt.run\u003Cstring>(\n `\n let input = \"\";\n for await (const chunk of process.stdin) input += chunk;\n globalThis.__return(input.trim().toUpperCase());\n `,\n { stdin: \"piped through stdin\", timeout: 10_000 },\n);\n```\n\nGuest code can also invoke host-side tools you register with the `tools` option\non `NodeRuntime.create()`: each becomes a named command the guest runs by name,\nround-tripping its JSON input to a handler on the host. For the full option and\nresult shapes, see the [TypeScript SDK reference](/docs/sdks/typescript).\n\n*[See Full Example](https://github.com/rivet-dev/secure-exec/tree/main/examples/docs/sdk-overview)*\n\n## Related\n\n\u003CCardGroup>\n \u003CCard title=\"Output Capture\" href=\"/docs/features/output-capture\">\n The result shape and streaming stdout/stderr as it is produced.\n \u003C/Card>\n \u003CCard title=\"Resident Runner\" href=\"/docs/features/resident-runner\">\n Reuse a live guest process for low-latency repeated execution.\n \u003C/Card>\n \u003CCard title=\"Child Processes\" href=\"/docs/features/child-processes\">\n spawn() long-running guests and the guest child_process surface.\n \u003C/Card>\n \u003CCard title=\"Resource Limits\" href=\"/docs/features/resource-limits\">\n Bound a run with timeout, AbortSignal, and the VM's limits.\n \u003C/Card>\n \u003CCard title=\"Bindings\" href=\"/docs/features/bindings\">\n Register host-side tools the guest invokes by name.\n \u003C/Card>\n\u003C/CardGroup>","src/content/docs/docs/features/executing-code.mdx","d346013a327e7a5a","docs/features/filesystem",{"id":123,"data":125,"body":128,"filePath":129,"digest":130,"deferredRender":19},{"title":126,"description":127},"Filesystem","A short overview of the Secure Exec filesystem, with a link to the canonical agentOS filesystem docs.","Each VM presents a normal POSIX filesystem to guest code, backed by a virtual filesystem inside the kernel. At a glance:\n\n- **Per-VM virtual filesystem**: Every VM gets its own isolated virtual filesystem. One VM cannot see or reach another VM's files.\n- **Never touches the host disk**: Guest filesystem calls are served entirely inside the kernel and never read or write the real host disk.\n- **Normal POSIX and Node APIs**: The standard `node:fs` and `node:fs/promises` APIs work as usual against the virtual filesystem, so ordinary programs run unchanged.\n- **Mountable backends**: You can project host-backed sources into the guest filesystem, Docker-style, including host directories and S3. Mounts are confined to their root, and the guest sees only the mounted subtree.\n- **`nodeModules` is a mount**: `NodeRuntime.create({ nodeModules })` is a convenience for a read-only host-directory mount. It projects a host `node_modules` tree at guest `/tmp/node_modules` using the same mount machinery as `mounts`, placed on the package-resolution path. See [Module loading](/docs/features/module-loading).\n\n## Full reference\n\nThe canonical filesystem API, including seeding files, host-boundary file exchange, and the full mount and backend configuration, is owned by agentOS.\n\n\u003CCard title=\"agentOS: Filesystem\" href=\"https://agentos-sdk.dev/docs/filesystem\">\n The complete filesystem API plus mount and backend configuration details.\n\u003C/Card>","src/content/docs/docs/features/filesystem.mdx","aab97ce4d6db5839","docs/features/module-loading",{"id":131,"data":133,"body":136,"filePath":137,"digest":138,"deferredRender":19},{"title":134,"description":135},"NPM & Module Loading","How sandboxed code resolves and loads modules.","Guest `import` and `require` resolve against the VM's virtual filesystem, never the host module loader. Resolution runs entirely inside the kernel. By default the guest sees an empty `node_modules`; project host packages into the VM with `nodeModules` (or `mounts`) to run real npm packages (including the TypeScript compiler) in-sandbox.\n\n## Loading Modules\n\n- Guest source runs as a standard ES module: `import`, `import.meta.url`, and top-level `await` all work.\n- Build a CommonJS `require` with `createRequire(import.meta.url)`.\n- Both paths resolve through the kernel's module loader.\n\n\u003CCodeSnippet file=\"examples/docs/feat-module-loading/src/index.mts\" region=\"loading-modules\" />\n\n```\nexitCode: 0\nguest stdout:\nresolved node:path via import -> /workspace/data/report.txt\nresolved node:os via require -> linux\n{\"basename\":\"report.txt\",\"joined\":\"/workspace/data/report.txt\",\"platform\":\"linux\"}\n```\n\n\u003CNote>Resolution runs inside the kernel against the guest's virtual filesystem. The guest only sees what is present there; mounting host `node_modules` (below) makes those packages part of that filesystem so they resolve like any other guest module.\u003C/Note>\n\n## Loading real npm packages\n\nPut package bytes on the guest filesystem, then let the in-kernel resolver walk them. Three ways to project them:\n\n- `create({ nodeModules })`: a convenience for a read-only host-directory mount that projects a whole host `node_modules` tree in one call. It uses the same mount machinery as `mounts`, defaulting to guest `/tmp/node_modules`, which is where the resolution walk begins for a program run by `exec()` / `run()` (each program is written under `/tmp`). Pass the object form (`{ hostPath, guestPath }`) to mount it elsewhere.\n- `create({ mounts })`: project one host directory at a time onto a guest path, Docker-style. Use a `mounts` entry per package when you want fine-grained control instead of the whole tree.\n- `create({ files })` or `rt.writeFile`: write bytes directly into the VM when you want to seed files instead of projecting a host tree.\n\nEither way the host filesystem is never exposed; the guest sees only the projected subtree or the bytes you write. For the full mount shapes see [the TypeScript SDK reference](/docs/sdks/typescript).\n\nThe example below points `nodeModules` at the host directory that holds `is-number`, then imports it from inside the VM. The guest resolves it the way Node would over a real filesystem, including through `createRequire`.\n\n\u003CCodeSnippet file=\"examples/docs/feat-module-loading/src/index.mts\" region=\"npm-packages\" />\n\n```\nexitCode: 0\nguest stdout:\nloaded real npm package is-number\n{\"isNumber(42)\":true,\"isNumber(\\\"3.14\\\")\":true,\"isNumber(\\\"nope\\\")\":false,\"sameModule\":true}\n```\n\n## node_modules resolution\n\nWhen a guest filesystem contains `node_modules`, the resolver matches naive Node.js resolution over it, Docker-style:\n\n- ancestor `node_modules` walk from the importing module up to the root,\n- `package.json` `exports`/`imports` and conditions,\n- `realpath`/symlink following.\n\nNo package-manager-specific heuristics: pnpm/yarn layouts resolve because the VFS exposes their symlinks, not because the resolver special-cases them.\n\n\u003CWarning>A `nodeModules` (or `mounts`) host mount confines reads to the mounted directory: symlinks are followed only while they stay **inside** the mount root. A single-project `npm`/`pnpm` install resolves fine because its symlinks (including the `.pnpm` store) live inside `node_modules`. A workspace/monorepo install is different: pnpm/yarn and `file:` deps symlink packages to the workspace root or an external store, **outside** the leaf `node_modules`. Those targets are not followed, and the guest import fails with `Cannot resolve module '\u003Cpkg>': not found`. Fix it by pointing the mount at a directory that contains every symlink target (for example the workspace root, mounted at the guest path the program resolves from) instead of the leaf `node_modules`.\u003C/Warning>\n\n## Seeding files directly\n\nWhen you don't have a host directory to mount, write bytes into the VM:\n\n```ts\n// At boot.\nconst rt = await NodeRuntime.create({\n files: { \"/tmp/node_modules/greet/index.js\": \"module.exports = () => 'hi';\" },\n});\n\n// Or after boot.\nawait rt.writeFile(\"/tmp/node_modules/greet/package.json\", '{\"main\":\"index.js\"}');\nconst bytes = await rt.readFile(\"/tmp/node_modules/greet/index.js\");\n```","src/content/docs/docs/features/module-loading.mdx","c06061fbc2b5bd9b","docs/features/networking",{"id":139,"data":141,"body":144,"filePath":145,"digest":146,"deferredRender":19},{"title":142,"description":143},"Networking","A short overview of Secure Exec networking, with a link to the canonical agentOS networking docs.","Secure Exec virtualizes all VM networking so guest code never touches the real host network. At a glance:\n\n- **One kernel socket table**: Guest `fetch()`, `node:http`, and raw sockets all flow through the kernel socket table, never the real host network.\n- **Loopback-only by default**: A guest can bind and reach loopback services inside its own VM, but the socket table stays hermetic and cannot reach a real host loopback service.\n- **Allowlist-gated egress**: Outbound networking is denied by default and opted into via the `network` permission, either allowing everything or scoping to specific patterns.\n- **Proxied host-to-guest**: Host loopback ports are not visible to the guest unless explicitly exposed through `loopbackExemptPorts`.\n\n## Full reference\n\nThe canonical networking API, permission rules, and egress details are owned by agentOS.\n\n\u003CCard title=\"agentOS: Networking\" href=\"https://agentos-sdk.dev/docs/networking\">\n The complete networking API, permission rules, and egress configuration.\n\u003C/Card>","src/content/docs/docs/features/networking.mdx","1ba5f6ed4b2dd3f4","docs/features/output-capture",{"id":147,"data":149,"body":152,"filePath":153,"digest":154,"deferredRender":19},{"title":150,"description":151},"Output Capture","Capture console output from sandboxed code.","`exec()` runs guest code and resolves with its captured output once the guest process exits.\n\n- `stdout` and `stderr` are buffered as separate strings, so output on one channel never bleeds into the other.\n- `exitCode` is the guest process's exit status.\n- Buffering into strings bounds host memory: each channel is held as one string, not an unbounded backlog of live chunks.\n\n## Capturing output\n\n\u003CCodeSnippet file=\"examples/docs/feat-output-capture/src/index.mts\" />\n\nPrints:\n\n```\nexitCode: 3\nstdout: \"hello from the sandbox\\n\"\nstderr: \"oops from the sandbox\\n\"\n```\n\n`process.exit(3)` is why `exitCode` is `3`.\n\n`run()` adds one more field. It resolves to the same `stdout`, `stderr`, and `exitCode`, plus a decoded `value` the guest hands back by calling `globalThis.__return(value)`:\n\n```ts\nconst { value, exitCode } = await rt.run(`\n\tconst sum = [1, 2, 3].reduce((a, b) => a + b, 0);\n\tglobalThis.__return({ sum });\n`);\n\nconsole.log(exitCode, value); // 0 { sum: 6 }\n```\n\n`value` is the JSON-decoded argument passed to `__return()`. It is only populated when `exitCode === 0` and the guest actually called `__return()`; otherwise it is `undefined`, while `stdout`, `stderr`, and `exitCode` are still captured.\n\nSee [the TypeScript SDK reference](/docs/sdks/typescript) for the full result and option shapes.\n\n## Streaming output\n\nPass `onStdout` / `onStderr` to observe output incrementally as it is produced. The full strings are still returned when the run ends.\n\n- Each callback receives a `Uint8Array` chunk. Decode text with a `TextDecoder`.\n- Available on both `exec()` and `run()`, and on `spawn()` via `NodeRuntimeSpawnOptions`.\n\n```ts\nconst decoder = new TextDecoder();\n\nconst { stdout, exitCode } = await rt.exec(\n\t`\n\t\tfor (let i = 0; i \u003C 3; i++) console.log(\"tick\", i);\n\t`,\n\t{\n\t\tonStdout: (chunk) => process.stdout.write(decoder.decode(chunk)),\n\t\tonStderr: (chunk) => process.stderr.write(decoder.decode(chunk)),\n\t},\n);\n// stdout still holds the complete buffered output after the run.\n```\n\n## Feeding input and cancelling\n\n`exec()`, `run()`, and `spawn()` take the same options object. Beyond the streaming hooks above, the common ones are `stdin` to pipe input in, `signal` to cancel, plus `env`, `cwd`, and `timeout`. The [TypeScript SDK reference](/docs/sdks/typescript) lists them all.\n\nFeed input and read everything back as buffered strings:\n\n```ts\nconst { stdout } = await rt.exec(\n\t`process.stdin.pipe(process.stdout);`,\n\t{ stdin: \"echo me back\\n\" },\n);\n// stdout === \"echo me back\\n\"\n```\n\nCancel an in-flight run with `signal`; the guest process is killed inside the VM and the call rejects with the abort reason:\n\n```ts\nconst controller = new AbortController();\nconst pending = rt.exec(\"while (true) {}\", { signal: controller.signal });\ncontroller.abort();\nawait pending.catch((err) => console.log(err.name)); // \"AbortError\"\n```\n\n## Common patterns\n\nUse `exitCode` to detect failure, with `stderr` for the diagnostic:\n\n```ts\nconst { stderr, exitCode } = await rt.exec(code);\nif (exitCode !== 0) throw new Error(`guest exited ${exitCode}: ${stderr}`);\n```\n\nFor long-running guests that never exit (dev servers), use `spawn()` instead: it returns a live `NodeRuntimeProcess` handle with the same `onStdout`/`onStderr` streaming, plus `writeStdin`, `kill`, and `wait()`.","src/content/docs/docs/features/output-capture.mdx","89cc853ac2e43c86","docs/features/permissions",{"id":155,"data":157,"body":160,"filePath":161,"digest":162,"deferredRender":19},{"title":158,"description":159},"Permissions","A short overview of Secure Exec permissions, with a link to the canonical agentOS permissions docs.","Secure Exec checks a per-domain permission policy against every guest syscall, so denied operations are rejected before any host resource is touched. At a glance:\n\n- **Per-domain policy**: Each domain (`fs`, `network`, `childProcess`, `process`, `env`, `tool`) is configured independently against every guest syscall.\n- **Allow, deny, or rules**: A domain takes a mode (`\"allow\"` or `\"deny\"`) or a rule set (`{ default, rules }`) for fine-grained control.\n- **Enforced before the host**: A denied operation is rejected with `EACCES` before any host resource (socket, file) is opened.\n- **Secure defaults**: The network is deny-by-default; filesystem, child processes, process info, and env are enabled so normal programs run.\n- **Trusted policy, untrusted subject**: The policy is set by the host, but the guest is the subject it binds. A denied domain holds even when guest code actively tries to escape it.\n\n## Full reference\n\nThe complete permission scopes, modes, and rule configuration are owned by agentOS.\n\n\u003CCard title=\"agentOS: Permissions\" href=\"https://agentos-sdk.dev/docs/permissions\">\n The complete permission scopes, modes, and rule configuration.\n\u003C/Card>","src/content/docs/docs/features/permissions.mdx","0c2d367f4b6af193","docs/features/resident-runner",{"id":163,"data":165,"body":168,"filePath":169,"digest":170,"deferredRender":19},{"title":166,"description":167},"Resident Runner","Reuse a live guest process for low-latency repeated execution.","Each `exec()` / `run()` call starts a fresh guest process, which is the right\ndefault for isolation between runs. When you run many small snippets against the\nsame runtime (an evaluation loop, a REPL, a test harness), that per-run process\nstartup dominates. A resident runner keeps one guest process alive and evaluates\neach snippet in it, so repeated calls are fast.\n\n\u003CNote>\nA resident runner trades per-run process isolation for speed: snippets share the\nsame process, so in-memory state can carry between calls. Use it for trusted,\nrepeated evaluation. For isolation between runs, use `exec()` / `run()`.\n\u003C/Note>\n\n## Creating and using a runner\n\n`createResidentRunner()` returns a handle with `exec()` and `dispose()`. Dispose\nit when you are done so the live process is torn down.\n\n```ts\nimport { NodeRuntime } from \"secure-exec\";\n\nconst rt = await NodeRuntime.create();\nconst runner = await rt.createResidentRunner();\ntry {\n const a = await runner.exec(\"console.log(1 + 1)\");\n const b = await runner.exec(\"console.log(2 + 2)\");\n console.log(a.stdout.trim(), b.stdout.trim()); // \"2\" \"4\"\n} finally {\n await runner.dispose();\n await rt.dispose();\n}\n```\n\nEach `runner.exec(code, options?)` resolves with the same\n`{ stdout, stderr, exitCode }` shape as `rt.exec()`. Pass `options.timeout` to\nbound a single evaluation.\n\n## When to use it\n\nA warm resident evaluation runs in roughly a millisecond, versus the hundreds of\nmilliseconds a cold run pays to stand up a guest process. Reach for a resident\nrunner when the same runtime runs many small snippets and the snippets are\ntrusted to share a process. See the measured difference in\n[Benchmarks](/docs/benchmarks).\n\n\u003CCard title=\"TypeScript SDK reference\" href=\"/docs/sdks/typescript\">\ncreateResidentRunner() and the NodeRuntimeResidentRunner handle.\n\u003C/Card>","src/content/docs/docs/features/resident-runner.mdx","ac84ebec1e57d3f0","docs/features/resource-limits",{"id":171,"data":173,"body":176,"filePath":177,"digest":178,"deferredRender":19},{"title":174,"description":175},"Resource Limits","Secure Exec resource limits, defaults, backpressure constants, and warning names.","Secure Exec bounds each VM with per-VM resource caps so untrusted guest code can never exhaust the host. At a glance:\n\n- **Per-VM caps**: Each VM gets its own ceilings on concurrent processes, open file descriptors, sockets, total filesystem bytes, and WASM stack depth.\n- **Kernel-enforced**: The kernel mediates and accounts for every allocation. There is no path for the guest to reach host resources around these limits.\n- **Guest-local failure**: A guest that exceeds a cap fails inside its own VM with a normal POSIX errno, exactly as it would on real Linux.\n- **Host is unaffected**: Hitting a limit terminates or fails the guest operation only; the sidecar and host process stay intact and the VM keeps running.\n- **Operator-raisable**: The caller configures the limits per VM and can raise or lower them to fit the workload.\n- **Observable**: Queue, resource, memory, and CPU limits emit `limit_warning` structured events and `WARN` logs as they approach or hit a cap.\n\n## Operator constants\n\nThese constants are the default caps behind the `limits.*` VM config fields.\n\n| Config field | Constant | Default |\n| --- | --- | --- |\n| `limits.resources.cpuCount` | `DEFAULT_VIRTUAL_CPU_COUNT` | `1` |\n| `limits.resources.maxProcesses` | `DEFAULT_MAX_PROCESSES` | `256` |\n| `limits.resources.maxOpenFds` | `DEFAULT_MAX_OPEN_FDS` | `256` |\n| `limits.resources.maxPipes` | `DEFAULT_MAX_PIPES` | `128` |\n| `limits.resources.maxPtys` | `DEFAULT_MAX_PTYS` | `128` |\n| `limits.resources.maxSockets` | `DEFAULT_MAX_SOCKETS` | `256` |\n| `limits.resources.maxConnections` | `DEFAULT_MAX_CONNECTIONS` | `256` |\n| `limits.resources.maxSocketBufferedBytes` | `DEFAULT_MAX_SOCKET_BUFFERED_BYTES` | `4 MiB` |\n| `limits.resources.maxSocketDatagramQueueLen` | `DEFAULT_MAX_SOCKET_DATAGRAM_QUEUE_LEN` | `1024` |\n| `limits.resources.maxFilesystemBytes` | `DEFAULT_MAX_FILESYSTEM_BYTES` | `64 MiB` |\n| `limits.resources.maxInodeCount` | `DEFAULT_MAX_INODE_COUNT` | `16384` |\n| `limits.resources.maxBlockingReadMs` | `DEFAULT_BLOCKING_READ_TIMEOUT_MS` | `5000 ms` |\n| `limits.resources.maxPreadBytes` | `DEFAULT_MAX_PREAD_BYTES` | `64 MiB` |\n| `limits.resources.maxFdWriteBytes` | `DEFAULT_MAX_FD_WRITE_BYTES` | `64 MiB` |\n| `limits.resources.maxProcessArgvBytes` | `DEFAULT_MAX_PROCESS_ARGV_BYTES` | `1 MiB` |\n| `limits.resources.maxProcessEnvBytes` | `DEFAULT_MAX_PROCESS_ENV_BYTES` | `1 MiB` |\n| `limits.resources.maxReaddirEntries` | `DEFAULT_MAX_READDIR_ENTRIES` | `4096` |\n| `limits.resources.maxWasmMemoryBytes` | `DEFAULT_MAX_WASM_MEMORY_BYTES` | `128 MiB` |\n| `limits.resources.maxWasmFuel` | none | unset, runtime default applies |\n| `limits.resources.maxWasmStackBytes` | none | unset, engine default applies |\n| `limits.http.maxFetchResponseBytes` | `DEFAULT_MAX_FETCH_RESPONSE_BYTES` | `1 MiB` |\n| `limits.tools.defaultToolTimeoutMs` | `DEFAULT_TOOL_TIMEOUT_MS` | `30000 ms` |\n| `limits.tools.maxToolTimeoutMs` | `MAX_TOOL_TIMEOUT_MS` | `300000 ms` |\n| `limits.tools.maxRegisteredToolkits` | `MAX_REGISTERED_TOOLKITS` | `64` |\n| `limits.tools.maxRegisteredToolsPerVm` | `MAX_REGISTERED_TOOLS_PER_VM` | `256` |\n| `limits.tools.maxToolsPerToolkit` | `MAX_TOOLS_PER_TOOLKIT` | `64` |\n| `limits.tools.maxToolSchemaBytes` | `MAX_TOOL_SCHEMA_BYTES` | `16 KiB` |\n| `limits.tools.maxToolExamplesPerTool` | `MAX_TOOL_EXAMPLES_PER_TOOL` | `16` |\n| `limits.tools.maxToolExampleInputBytes` | `MAX_TOOL_EXAMPLE_INPUT_BYTES` | `4 KiB` |\n| `limits.plugins.maxPersistedManifestBytes` | `MAX_PERSISTED_MANIFEST_BYTES` | `64 MiB` |\n| `limits.plugins.maxPersistedManifestFileBytes` | `MAX_PERSISTED_MANIFEST_FILE_BYTES` | `1 GiB` |\n| `limits.acp.maxReadLineBytes` | `DEFAULT_ACP_MAX_READ_LINE_BYTES` | `16 MiB` |\n| `limits.acp.stdoutBufferByteLimit` | `DEFAULT_ACP_STDOUT_BUFFER_BYTE_LIMIT` | `1 MiB` |\n| `limits.jsRuntime.v8HeapLimitMb` | `DEFAULT_V8_HEAP_LIMIT_MB` | `128 MiB` |\n| `limits.jsRuntime.capturedOutputLimitBytes` | `DEFAULT_JS_CAPTURED_OUTPUT_LIMIT_BYTES` | `16 MiB` |\n| `limits.jsRuntime.stdinBufferLimitBytes` | `DEFAULT_JS_STDIN_BUFFER_LIMIT_BYTES` | `16 MiB` |\n| `limits.jsRuntime.eventPayloadLimitBytes` | `DEFAULT_JS_EVENT_PAYLOAD_LIMIT_BYTES` | `1 MiB` |\n| `limits.jsRuntime.v8IpcMaxFrameBytes` | `DEFAULT_V8_IPC_MAX_FRAME_BYTES` | `64 MiB` |\n| `limits.jsRuntime.syncRpcWaitTimeoutMs` | none | unset, engine default applies |\n| `limits.python.outputBufferMaxBytes` | `DEFAULT_PYTHON_OUTPUT_BUFFER_MAX_BYTES` | `1 MiB` |\n| `limits.python.executionTimeoutMs` | `DEFAULT_PYTHON_EXECUTION_TIMEOUT_MS` | `300000 ms` |\n| `limits.python.maxOldSpaceMb` | `DEFAULT_PYTHON_MAX_OLD_SPACE_MB` | `0`, Pyodide engine default |\n| `limits.python.vfsRpcTimeoutMs` | `DEFAULT_PYTHON_VFS_RPC_TIMEOUT_MS` | `30000 ms` |\n| `limits.wasm.maxModuleFileBytes` | `DEFAULT_WASM_MAX_MODULE_FILE_BYTES` | `256 MiB` |\n| `limits.wasm.capturedOutputLimitBytes` | `DEFAULT_WASM_CAPTURED_OUTPUT_LIMIT_BYTES` | `16 MiB` |\n| `limits.wasm.syncReadLimitBytes` | `DEFAULT_WASM_SYNC_READ_LIMIT_BYTES` | `16 MiB` |\n\n## Backpressure constants\n\nThese internal queue caps are not per-VM config fields. They are tracked so slow consumers produce `limit_warning` events instead of silent stalls.\n\n| Warning name | Constant | Default |\n| --- | --- | --- |\n| `javascript_event_channel` | `JAVASCRIPT_EVENT_CHANNEL_CAPACITY` | `512 frames` |\n| `v8_session_frames` | `V8_SESSION_FRAME_CHANNEL_CAPACITY` | `1024 frames` |\n| `sidecar_stdin_frames` | `MAX_STDIN_FRAME_QUEUE` | `128 frames` |\n| `sidecar_stdout_frames` | `MAX_STDOUT_FRAME_QUEUE` | `4096 frames` |\n| `completed_sidecar_responses` | `MAX_COMPLETED_SIDECAR_RESPONSES` | `10000 responses` |\n\n## Audited constants\n\nThe limits audit classifies every limit-shaped constant as `policy`, `policy-deferred`, or `invariant`. Keep this table in sync with `crates/sidecar/tests/fixtures/limits-inventory.json`.\n\n| Constant | Class | Source |\n| --- | --- | --- |\n| `MAX_SYMLINK_DEPTH` | `invariant` | `crates/execution/assets/v8-bridge.source.js` |\n| `MAX_BENCHMARK_ITERATIONS` | `invariant` | `crates/execution/src/benchmark.rs` |\n| `MAX_BENCHMARK_WARMUP_ITERATIONS` | `invariant` | `crates/execution/src/benchmark.rs` |\n| `JAVASCRIPT_CAPTURED_OUTPUT_LIMIT_BYTES` | `policy` | `crates/execution/src/javascript.rs` |\n| `JAVASCRIPT_EVENT_CHANNEL_CAPACITY` | `invariant` | `crates/execution/src/javascript.rs` |\n| `JAVASCRIPT_EVENT_PAYLOAD_LIMIT_BYTES` | `policy` | `crates/execution/src/javascript.rs` |\n| `KERNEL_STDIN_BUFFER_LIMIT_BYTES` | `policy` | `crates/execution/src/javascript.rs` |\n| `NODE_SYNC_RPC_RESPONSE_QUEUE_CAPACITY` | `invariant` | `crates/execution/src/javascript.rs` |\n| `DEFAULT_NODE_IMPORT_CACHE_MATERIALIZE_TIMEOUT` | `invariant` | `crates/execution/src/node_import_cache.rs` |\n| `DEFAULT_PYTHON_EXECUTION_TIMEOUT_MS` | `policy` | `crates/execution/src/python.rs` |\n| `DEFAULT_PYTHON_MAX_OLD_SPACE_MB` | `policy` | `crates/execution/src/python.rs` |\n| `DEFAULT_PYTHON_OUTPUT_BUFFER_MAX_BYTES` | `policy` | `crates/execution/src/python.rs` |\n| `DEFAULT_PYTHON_VFS_RPC_TIMEOUT_MS` | `policy` | `crates/execution/src/python.rs` |\n| `V8_SESSION_FRAME_CHANNEL_CAPACITY` | `invariant` | `crates/execution/src/v8_host.rs` |\n| `MAX_FRAME_SIZE` | `policy` | `crates/execution/src/v8_ipc.rs` |\n| `DEFAULT_WASM_EXECUTION_TIMEOUT_MS` | `policy-deferred` | `crates/execution/src/wasm.rs` |\n| `DEFAULT_WASM_PREWARM_TIMEOUT_MS` | `invariant` | `crates/execution/src/wasm.rs` |\n| `MAX_SYNC_WASM_PREWARM_MODULE_BYTES` | `invariant` | `crates/execution/src/wasm.rs` |\n| `MAX_WASM_IMPORT_SECTION_ENTRIES` | `invariant` | `crates/execution/src/wasm.rs` |\n| `MAX_WASM_MEMORY_SECTION_ENTRIES` | `invariant` | `crates/execution/src/wasm.rs` |\n| `MAX_WASM_MODULE_FILE_BYTES` | `policy` | `crates/execution/src/wasm.rs` |\n| `MAX_WASM_VARUINT_BYTES` | `invariant` | `crates/execution/src/wasm.rs` |\n| `WASM_CAPTURED_OUTPUT_LIMIT_BYTES` | `policy` | `crates/execution/src/wasm.rs` |\n| `WASM_SYNC_READ_LIMIT_BYTES` | `policy` | `crates/execution/src/wasm.rs` |\n| `DEFAULT_STREAM_DEVICE_READ_BYTES` | `invariant` | `crates/kernel/src/device_layer.rs` |\n| `MAX_FDS_PER_PROCESS` | `invariant` | `crates/kernel/src/fd_table.rs` |\n| `SHEBANG_LINE_MAX_BYTES` | `invariant` | `crates/kernel/src/kernel.rs` |\n| `MAX_SNAPSHOT_DEPTH` | `invariant` | `crates/vfs/src/posix/overlay_fs.rs` |\n| `MAX_PIPE_BUFFER_BYTES` | `invariant` | `crates/kernel/src/pipe_manager.rs` |\n| `MAX_ALLOCATED_PID` | `invariant` | `crates/kernel/src/process_table.rs` |\n| `MAX_SIGNAL` | `invariant` | `crates/kernel/src/process_table.rs` |\n| `MAX_CANON` | `invariant` | `crates/kernel/src/pty.rs` |\n| `MAX_PTY_BUFFER_BYTES` | `invariant` | `crates/kernel/src/pty.rs` |\n| `DEFAULT_BLOCKING_READ_TIMEOUT_MS` | `policy` | `crates/kernel/src/resource_accounting.rs` |\n| `DEFAULT_MAX_CONNECTIONS` | `policy` | `crates/kernel/src/resource_accounting.rs` |\n| `DEFAULT_MAX_FD_WRITE_BYTES` | `policy` | `crates/kernel/src/resource_accounting.rs` |\n| `DEFAULT_MAX_FILESYSTEM_BYTES` | `policy` | `crates/vfs/src/posix/usage.rs` |\n| `DEFAULT_MAX_INODE_COUNT` | `policy` | `crates/vfs/src/posix/usage.rs` |\n| `DEFAULT_MAX_OPEN_FDS` | `policy` | `crates/kernel/src/resource_accounting.rs` |\n| `DEFAULT_MAX_PIPES` | `policy` | `crates/kernel/src/resource_accounting.rs` |\n| `DEFAULT_MAX_PREAD_BYTES` | `policy` | `crates/kernel/src/resource_accounting.rs` |\n| `DEFAULT_MAX_PROCESS_ARGV_BYTES` | `policy` | `crates/kernel/src/resource_accounting.rs` |\n| `DEFAULT_MAX_PROCESS_ENV_BYTES` | `policy` | `crates/kernel/src/resource_accounting.rs` |\n| `DEFAULT_MAX_PROCESSES` | `policy` | `crates/kernel/src/resource_accounting.rs` |\n| `DEFAULT_MAX_PTYS` | `policy` | `crates/kernel/src/resource_accounting.rs` |\n| `DEFAULT_MAX_READDIR_ENTRIES` | `policy` | `crates/kernel/src/resource_accounting.rs` |\n| `DEFAULT_MAX_WASM_MEMORY_BYTES` | `policy` | `crates/kernel/src/resource_accounting.rs` |\n| `DEFAULT_MAX_SOCKET_BUFFERED_BYTES` | `policy` | `crates/kernel/src/resource_accounting.rs` |\n| `DEFAULT_MAX_SOCKET_DATAGRAM_QUEUE_LEN` | `policy` | `crates/kernel/src/resource_accounting.rs` |\n| `DEFAULT_MAX_SOCKETS` | `policy` | `crates/kernel/src/resource_accounting.rs` |\n| `MAX_PATH_LENGTH` | `invariant` | `crates/vfs/src/posix/vfs.rs` |\n| `MAX_SYMLINK_DEPTH` | `invariant` | `crates/vfs/src/posix/vfs.rs` |\n| `MAX_PATH` | `invariant` | `crates/vfs/src/engine/types.rs` |\n| `MAX_SYMLINK_DEPTH` | `invariant` | `crates/vfs/src/engine/types.rs` |\n| `DEFAULT_METADATA_CACHE_ENTRIES` | `invariant` | `crates/sidecar/src/plugins/chunked_local.rs` |\n| `DEFAULT_METADATA_CACHE_ENTRIES` | `invariant` | `crates/sidecar/src/plugins/chunked_s3.rs` |\n| `CONTROL_FRAME_QUEUE_CAPACITY` | `invariant` | `crates/secure-exec-client/src/transport.rs` |\n| `EVENT_CHANNEL_CAPACITY` | `invariant` | `crates/secure-exec-client/src/transport.rs` |\n| `PENDING_REQUEST_LIMIT` | `invariant` | `crates/secure-exec-client/src/transport.rs` |\n| `REQUEST_FRAME_QUEUE_CAPACITY` | `invariant` | `crates/secure-exec-client/src/transport.rs` |\n| `DEFAULT_KERNEL_STDIN_READ_MAX_BYTES` | `invariant` | `crates/sidecar/src/execution.rs` |\n| `DEFAULT_KERNEL_STDIN_READ_TIMEOUT_MS` | `invariant` | `crates/sidecar/src/execution.rs` |\n| `EXITED_PROCESS_SNAPSHOT_RETENTION` | `invariant` | `crates/sidecar/src/execution.rs` |\n| `JAVASCRIPT_NET_POLL_MAX_WAIT` | `invariant` | `crates/sidecar/src/execution.rs` |\n| `MAX_JAVASCRIPT_COMMAND_REDIRECT_DEPTH` | `invariant` | `crates/sidecar/src/execution.rs` |\n| `MAX_PER_PROCESS_STATE_HANDLES` | `policy-deferred` | `crates/sidecar/src/execution.rs` |\n| `SQLITE_JS_SAFE_INTEGER_MAX` | `invariant` | `crates/sidecar/src/execution.rs` |\n| `VM_FETCH_BUFFER_LIMIT_BYTES` | `policy` | `crates/sidecar/src/execution.rs` |\n| `DEFAULT_ACP_MAX_READ_LINE_BYTES` | `policy` | `crates/sidecar/src/limits.rs` |\n| `DEFAULT_ACP_STDOUT_BUFFER_BYTE_LIMIT` | `policy` | `crates/sidecar/src/limits.rs` |\n| `DEFAULT_JS_CAPTURED_OUTPUT_LIMIT_BYTES` | `policy` | `crates/sidecar/src/limits.rs` |\n| `DEFAULT_JS_EVENT_PAYLOAD_LIMIT_BYTES` | `policy` | `crates/sidecar/src/limits.rs` |\n| `DEFAULT_JS_STDIN_BUFFER_LIMIT_BYTES` | `policy` | `crates/sidecar/src/limits.rs` |\n| `DEFAULT_MAX_FETCH_RESPONSE_BYTES` | `policy` | `crates/sidecar/src/limits.rs` |\n| `DEFAULT_PYTHON_EXECUTION_TIMEOUT_MS` | `policy` | `crates/sidecar/src/limits.rs` |\n| `DEFAULT_PYTHON_MAX_OLD_SPACE_MB` | `policy` | `crates/sidecar/src/limits.rs` |\n| `DEFAULT_PYTHON_OUTPUT_BUFFER_MAX_BYTES` | `policy` | `crates/sidecar/src/limits.rs` |\n| `DEFAULT_PYTHON_VFS_RPC_TIMEOUT_MS` | `policy` | `crates/sidecar/src/limits.rs` |\n| `DEFAULT_TOOL_TIMEOUT_MS` | `policy` | `crates/sidecar/src/limits.rs` |\n| `DEFAULT_V8_IPC_MAX_FRAME_BYTES` | `policy` | `crates/sidecar/src/limits.rs` |\n| `DEFAULT_V8_HEAP_LIMIT_MB` | `policy` | `crates/sidecar/src/limits.rs` |\n| `DEFAULT_WASM_CAPTURED_OUTPUT_LIMIT_BYTES` | `policy` | `crates/sidecar/src/limits.rs` |\n| `DEFAULT_WASM_MAX_MODULE_FILE_BYTES` | `policy` | `crates/sidecar/src/limits.rs` |\n| `DEFAULT_WASM_SYNC_READ_LIMIT_BYTES` | `policy` | `crates/sidecar/src/limits.rs` |\n| `MAX_PERSISTED_MANIFEST_BYTES` | `policy` | `crates/sidecar/src/limits.rs` |\n| `MAX_PERSISTED_MANIFEST_FILE_BYTES` | `policy` | `crates/sidecar/src/limits.rs` |\n| `MAX_REGISTERED_TOOLKITS` | `policy` | `crates/sidecar/src/limits.rs` |\n| `MAX_REGISTERED_TOOLS_PER_VM` | `policy` | `crates/sidecar/src/limits.rs` |\n| `MAX_TOOL_EXAMPLE_INPUT_BYTES` | `policy` | `crates/sidecar/src/limits.rs` |\n| `MAX_TOOL_EXAMPLES_PER_TOOL` | `policy` | `crates/sidecar/src/limits.rs` |\n| `MAX_TOOL_SCHEMA_BYTES` | `policy` | `crates/sidecar/src/limits.rs` |\n| `MAX_TOOL_TIMEOUT_MS` | `policy` | `crates/sidecar/src/limits.rs` |\n| `MAX_TOOLS_PER_TOOLKIT` | `policy` | `crates/sidecar/src/limits.rs` |\n| `MAX_PERSISTED_MANIFEST_BYTES` | `policy` | `crates/sidecar/src/plugins/google_drive.rs` |\n| `MAX_PERSISTED_MANIFEST_FILE_BYTES` | `policy` | `crates/sidecar/src/plugins/google_drive.rs` |\n| `MAX_HOST_DIR_READ_BYTES` | `policy` | `crates/sidecar/src/plugins/host_dir.rs` |\n| `DEFAULT_MAX_FULL_READ_BYTES` | `policy-deferred` | `crates/sidecar/src/plugins/sandbox_agent.rs` |\n| `DEFAULT_PROCESS_TIMEOUT_MS` | `policy-deferred` | `crates/sidecar/src/plugins/sandbox_agent.rs` |\n| `DEFAULT_TIMEOUT_MS` | `policy-deferred` | `crates/sidecar/src/plugins/sandbox_agent.rs` |\n| `DEFAULT_COMPLETED_RESPONSE_CAP` | `invariant` | `crates/sidecar/src/protocol.rs` |\n| `DEFAULT_MAX_FRAME_BYTES` | `policy` | `crates/sidecar/src/protocol.rs` |\n| `DEFAULT_MAX_FRAME_BYTES` | `invariant` | `crates/sidecar/src/wire.rs` |\n| `MAX_COMPLETED_SIDECAR_RESPONSES` | `invariant` | `crates/sidecar/src/service.rs` |\n| `MAX_OUTBOUND_SIDECAR_REQUESTS` | `invariant` | `crates/sidecar/src/service.rs` |\n| `MAX_PENDING_SIDECAR_RESPONSES` | `invariant` | `crates/sidecar/src/service.rs` |\n| `MAX_PROCESS_EVENT_QUEUE` | `invariant` | `crates/sidecar/src/service.rs` |\n| `HOST_REALPATH_MAX_SYMLINK_DEPTH` | `invariant` | `crates/sidecar/src/state.rs` |\n| `VM_LISTEN_PORT_MAX_METADATA_KEY` | `invariant` | `crates/sidecar/src/state.rs` |\n| `MAX_EVENT_READY_QUEUE` | `invariant` | `crates/sidecar/src/stdio.rs` |\n| `MAX_STDIN_FRAME_QUEUE` | `invariant` | `crates/sidecar/src/stdio.rs` |\n| `MAX_STDOUT_FRAME_QUEUE` | `invariant` | `crates/sidecar/src/stdio.rs` |\n| `DEFAULT_TOOL_TIMEOUT_MS` | `policy` | `crates/sidecar/src/tools.rs` |\n| `MAX_REGISTERED_TOOLKITS` | `policy` | `crates/sidecar/src/tools.rs` |\n| `MAX_REGISTERED_TOOLS_PER_VM` | `policy` | `crates/sidecar/src/tools.rs` |\n| `MAX_TOOL_DESCRIPTION_LENGTH` | `policy-deferred` | `crates/sidecar/src/tools.rs` |\n| `MAX_TOOL_EXAMPLE_INPUT_BYTES` | `policy` | `crates/sidecar/src/tools.rs` |\n| `MAX_TOOL_EXAMPLES_PER_TOOL` | `policy` | `crates/sidecar/src/tools.rs` |\n| `MAX_TOOL_NAME_LENGTH` | `policy-deferred` | `crates/sidecar/src/tools.rs` |\n| `MAX_TOOL_SCHEMA_BYTES` | `policy` | `crates/sidecar/src/tools.rs` |\n| `MAX_TOOL_SCHEMA_DEPTH` | `invariant` | `crates/sidecar/src/tools.rs` |\n| `MAX_TOOL_TIMEOUT_MS` | `policy` | `crates/sidecar/src/tools.rs` |\n| `MAX_TOOLKIT_NAME_LENGTH` | `policy-deferred` | `crates/sidecar/src/tools.rs` |\n| `MAX_TOOLS_PER_TOOLKIT` | `policy` | `crates/sidecar/src/tools.rs` |\n| `MAX_VM_LAYERS` | `policy-deferred` | `crates/sidecar/src/vm.rs` |\n| `MAX_CBOR_BRIDGE_CONTAINER_ITEMS` | `invariant` | `crates/v8-runtime/src/bridge.rs` |\n| `MAX_CBOR_BRIDGE_DEPTH` | `invariant` | `crates/v8-runtime/src/bridge.rs` |\n| `MAX_PENDING_PROMISES` | `invariant` | `crates/v8-runtime/src/bridge.rs` |\n| `MAX_VM_CONTEXTS` | `invariant` | `crates/v8-runtime/src/bridge.rs` |\n| `SESSION_OUTPUT_CHANNEL_CAPACITY` | `invariant` | `crates/v8-runtime/src/embedded_runtime.rs` |\n| `MAX_CJS_NAMED_EXPORTS` | `invariant` | `crates/v8-runtime/src/execution.rs` |\n| `MAX_CJS_RUNTIME_EXPORT_NAME_LEN` | `invariant` | `crates/v8-runtime/src/execution.rs` |\n| `MAX_MODULE_BATCH_RESOLVE_RESPONSE_BYTES` | `invariant` | `crates/v8-runtime/src/execution.rs` |\n| `MAX_MODULE_PREFETCH_BATCH_SIZE` | `invariant` | `crates/v8-runtime/src/execution.rs` |\n| `MAX_MODULE_PREFETCH_GRAPH_MODULES` | `invariant` | `crates/v8-runtime/src/execution.rs` |\n| `MAX_MODULE_RESOLVE_CACHE_ENTRIES` | `invariant` | `crates/v8-runtime/src/execution.rs` |\n| `MAX_MODULE_RESOLVE_MODULES` | `invariant` | `crates/v8-runtime/src/execution.rs` |\n| `MAX_FRAME_SIZE` | `policy` | `crates/v8-runtime/src/ipc_binary.rs` |\n| `MAX_UNHANDLED_PROMISE_REJECTIONS` | `invariant` | `crates/v8-runtime/src/isolate.rs` |\n| `NEAR_HEAP_LIMIT_HEADROOM_BYTES` | `invariant` | `crates/v8-runtime/src/isolate.rs` |\n| `MAX_DEFERRED_SESSION_COMMANDS` | `invariant` | `crates/v8-runtime/src/session.rs` |\n| `MAX_DEFERRED_SYNC_MESSAGES` | `invariant` | `crates/v8-runtime/src/session.rs` |\n| `SESSION_COMMAND_CHANNEL_CAPACITY` | `invariant` | `crates/v8-runtime/src/session.rs` |\n| `MAX_SNAPSHOT_BLOB_BYTES` | `invariant` | `crates/v8-runtime/src/snapshot.rs` |\n| `MAX_V8_BRIDGE_CODE_BYTES` | `invariant` | `crates/v8-runtime/src/snapshot.rs` |\n| `TRAILING_OUTPUT_DRAIN_MAX_MS` | `invariant` | `packages/core/src/kernel-proxy.ts` |\n| `DEFAULT_SIDECAR_EVENT_BUFFER_CAPACITY` | `policy-deferred` | `packages/core/src/native-client.ts` |\n| `DEFAULT_SIDECAR_FRAME_TIMEOUT_MS` | `policy-deferred` | `packages/core/src/native-client.ts` |\n| `MAX_SYMLINK_DEPTH` | `invariant` | `packages/core/src/test-runtime.ts` |\n\n## Warning names\n\nThe limit registry emits stable names in `limit_warning.detail.limit`.\n`limits.resources.maxWasmStackBytes` is audited as a configured constant above, but it does not emit `limit_warning` until runtime stack enforcement has a reliable exhaustion edge.\n\nWhen a warning fires depends on whether the limit has a continuously-sampled usage:\n\n- **Queue**, **Resource**, and **CPU** limits emit an **edge-triggered ~80% approach warning** (re-armed once usage drains back below ~50%), so the operator gets a heads-up *before* the cap is reached. The CPU budgets (`v8_cpu_time_ms`, `v8_wall_clock_ms`, `wasm_fuel_ms`) are sampled by the execution watchdogs; the queue/resource gauges are sampled as items flow through them.\n- **Memory** limits (`v8_heap_bytes`, `wasm_memory_bytes`) emit at the **terminal edge** — V8's near-heap-limit callback fires as the isolate is about to exceed its heap cap, and WASM memory is checked at module-instantiation time. There is no separate 80% heap sample because a V8 isolate cannot be safely read from the watchdog thread.\n\nCPU budgets therefore emit both the ~80% approach warning *and* a terminal exhaustion warning when the watchdog finally terminates execution.\n\n| Category | Warning names |\n| --- | --- |\n| Queue | `javascript_event_channel`, `v8_session_frames`, `sidecar_stdin_frames`, `sidecar_stdout_frames`, `completed_sidecar_responses`, `pending_process_events`, `pending_sidecar_responses`, `outbound_sidecar_requests` |\n| Resource | `vm_processes`, `vm_open_fds`, `vm_pipes`, `vm_ptys`, `vm_sockets`, `vm_connections`, `vm_socket_buffered_bytes`, `vm_socket_datagram_queue_len`, `vm_filesystem_bytes`, `vm_inodes` |\n| Memory | `v8_heap_bytes`, `wasm_memory_bytes` |\n| CPU | `v8_cpu_time_ms`, `v8_wall_clock_ms`, `wasm_fuel_ms` |\n\n## Related agentOS docs\n\nagentOS layers its own session and adapter limits on top of Secure Exec.\n\n\u003CCardGroup>\n \u003CCard title=\"agentOS: Resource Limits\" href=\"https://agentos-sdk.dev/docs/resource-limits\">\n The complete set of per-VM resource limits, defaults, and configuration options.\n \u003C/Card>\n\u003C/CardGroup>","src/content/docs/docs/features/resource-limits.mdx","25e050e3fbf9f413","docs/features/runtime-platform",{"id":179,"data":181,"body":184,"filePath":185,"digest":186,"deferredRender":19},{"title":182,"description":183},"Runtime & Platform","Customize the host environment guest code sees (the full Node.js surface today), plus the platform ladder (node, browser, neutral, bare) the kernel models.","`NodeRuntime.create()` shapes the host environment guest code sees before it\nboots, and the kernel models that environment as a ladder of platforms (`node`,\n`browser`, `neutral`, `bare`). Guest code always runs inside a kernel-backed V8\nisolate with zero host escapes: every syscall (filesystem, network, child\nprocess) goes through the kernel, never the real host.\n\nThis page covers the customization surface: seeding and selecting the host\nenvironment, then the `moduleResolution` and `allowedBuiltins` knobs the wire\nconfig exposes. Start by probing the default `node` surface:\n\n\u003CCodeSnippet file=\"examples/docs/feat-runtime-platform/src/index.mts\" />\n\nOutput, the guest host environment as seen from inside the isolate:\n\n```text\n{\n platform: 'linux',\n hasProcess: true,\n hasBuffer: true,\n nodeVersion: '22.0.0',\n sha256: 'fa7ce60dac0cc1bfe7424a68e47ad3d712345cf936431bb147cd5f5de0371a4a',\n joinedPath: '/home/agentos/report.txt'\n}\n```\n\n\u003CNote>\n**Guest `run()` and `exec()` code both run as ES modules.** Both `rt.run()` and\n`rt.exec()` write your code into an `.mjs` module, so top-level `import` and\ntop-level `await` work in either. `run()` injects a `globalThis.__return(value)`\nhelper you call to hand a JSON-serializable value back to the host (delivered as\n`result.value`); the example uses dynamic `await import(\"node:…\")` purely to keep\nthe snippet a single expression body.\n\u003C/Note>\n\n## Host environment (the `node` surface)\n\nAvailable to guest code on the default platform:\n\n- **Node globals**: `process`, `Buffer`, `require`, `module`, `__dirname`, `__filename`.\n- **`node:*` builtins**: `fs`, `path`, `crypto`, `http`, `net`, `os`, `child_process`, `dns`, and the rest of the Node standard library.\n- **Node identity**: virtualized `process.versions` (Node `22.0.0`), `process.platform` (`linux`), `execPath`, and `pid`/`ppid`/`uid`/`gid`.\n- **Web platform**: `fetch`, `URL`, `TextEncoder`/`TextDecoder`, WebCrypto, `structuredClone`, `Blob`, `AbortController`.\n- **Universal primitives**: `console`, timers (`setTimeout`/`setInterval`/…), `queueMicrotask`.\n- **Language + Wasm**: the ECMAScript spec globals plus `WebAssembly`.\n\nEvery one of these is kernel-backed. `fetch` and `node:net`/`node:http` route\nthrough the kernel socket table (and are denied by default until you grant\n`network`); `node:fs` sees only the VM's virtual filesystem; `node:child_process`\nspawns kernel-managed processes.\n\n### Seeding the host environment\n\n`NodeRuntime.create()` shapes what the guest sees before and after boot:\n\n```ts\nconst rt = await NodeRuntime.create({\n\tenv: { API_BASE: \"https://example.test\" }, // guest process env\n\tcwd: \"/workspace\", // default working dir\n\tfiles: { \"/root/data.json\": '{\"ok\":true}' }, // seed VFS bytes\n\tmounts: [ // project host dirs, Docker-style, lazy\n\t\t{ guestPath: \"/root/node_modules/typescript\", hostPath: \"/abs/typescript\", readOnly: true },\n\t],\n\tpermissions: { network: \"allow\" }, // merged over secure default (network denied)\n\ttools: { // host capabilities the guest calls as commands\n\t\tadd: {\n\t\t\tdescription: \"Add two numbers\",\n\t\t\tinputSchema: { type: \"object\", properties: { a: { type: \"number\" }, b: { type: \"number\" } }, required: [\"a\", \"b\"] },\n\t\t\thandler: ({ a, b }: { a: number; b: number }) => ({ sum: a + b }),\n\t\t},\n\t},\n\tloopbackExemptPorts: [3000], // let non-loopback connections reach this port\n\tcommandsDir: \"/abs/wasm/commands\", // override the WASM `sh`/coreutils dir\n});\n```\n\n- `files` copies bytes into the VFS up front; `mounts` reads host trees lazily through the VFS, so large `node_modules` are not copied as a blob.\n- `permissions` merges over a secure default (`fs`/`childProcess`/`process`/`env` allowed, `network` denied), so `{ network: \"allow\" }` is enough to opt in.\n- `tools` auto-grants the `tool` scope when you set no `tool` policy; the guest invokes a tool by name with `--json` input over `node:child_process`.\n\nAfter boot, the same surface is reachable on the live runtime:\n\n```ts\nawait rt.writeFile(\"/root/late.json\", '{\"added\":\"after boot\"}');\nconst bytes = await rt.readFile(\"/root/late.json\"); // Uint8Array\nawait rt.registerTools({\n\tnow: { description: \"epoch ms\", inputSchema: { type: \"object\" }, handler: () => Date.now() },\n});\n```\n\n### Driving a guest dev server from the host\n\nSpawn a long-running guest, wait for it to listen, then drive an HTTP request\ninto it from the host. This works even with egress denied, because the request\nflows through the kernel socket table rather than the real host network:\n\n```ts\nconst server = await rt.spawn(`\n\timport http from \"node:http\";\n\thttp.createServer((_, res) => res.end(\"ok\")).listen(3000);\n`);\nconst listener = await rt.waitForListener({ port: 3000 });\nconst res = await rt.fetch(listener.port ?? 3000, { path: \"/\" });\nserver.kill();\nawait server.wait();\n```\n\nFor the full set of run methods (`exec`/`run`/`spawn`/`fetch`/`waitForListener`)\nand their per-run options (`env`, `cwd`, `stdin`, `timeout`, `signal`,\n`onStdout`/`onStderr`), see the TypeScript SDK reference:\n\n\u003CCard title=\"NodeRuntime run methods and options\" href=\"/docs/sdks/typescript\">\nFull signatures for exec/run/spawn/fetch/waitForListener and the shared per-run options.\n\u003C/Card>\n\n## The platform ladder\n\nThe kernel models the guest host environment as a ladder, using esbuild's\nvocabulary (`node` / `browser` / `neutral`) plus `bare` for the language-only\ntier esbuild has no name for. `NodeRuntime` always runs the top rung (`node`);\nthe lower rungs are described here for context and are **not currently selectable\nin Secure Exec** (see the note below).\n\n| Capability | `node` | `browser` | `neutral` | `bare` |\n|---|:---:|:---:|:---:|:---:|\n| Node globals | ✅ | No | No | No |\n| `node:*` builtins | ✅ | No | No | No |\n| Node identity | ✅ | No | No | No |\n| Web platform | ✅ | ✅ | No | No |\n| Universal primitives | ✅ | ✅ | ✅ | No |\n| Language + Wasm | ✅ | ✅ | ✅ | ✅ |\n\n- **`node`** (the default): full Node.js compatibility. Nothing removed.\n- **`browser`**: a browser/Deno-like runtime. The Node surface is gone; web-standard globals remain. `crypto` is the WebCrypto object (`crypto.subtle`, `crypto.getRandomValues`), *not* the `node:crypto` module, so `crypto.randomBytes`/`crypto.createHash` are absent.\n- **`neutral`**: universal primitives only (`console`, timers, `queueMicrotask`) plus the language. No `fetch`/`URL`/WebCrypto, no Node.\n- **`bare`**: language only: the ECMAScript spec globals plus `WebAssembly`. No `console`, no timers, no `fetch`. The caller provides any host functionality the guest needs.\n\n`WebAssembly` stays available on **every tier**, including `bare`. Compilation\nhappens inside the isolate and is not a host escape.\n\n\u003CWarning>\n**Platform selection is not configurable in Secure Exec yet.** The kernel's wire\nprotocol carries a `jsRuntime` config with `platform`, `moduleResolution`, and\n`allowedBuiltins` fields. The tiers are real in the kernel, but\n`NodeRuntime.create()` does **not** plumb those fields through: it always boots\nthe VM on the `node` platform with full Node module resolution. There is no\n`NodeRuntime.create()` option to select `browser`/`neutral`/`bare`, change module\nresolution, or restrict the builtin allow-list today. The sections below document\nthe intended model for those fields, not a `create()` option you can pass.\n\u003C/Warning>\n\n## `moduleResolution`: how imports resolve\n\n`moduleResolution` is an independent axis of the `jsRuntime` config (any\ncombination with `platform` is valid). Set it alongside `platform` to lock down\nhow `import`/`require` specifiers resolve:\n\n```ts\nconst config: CreateVmConfig = {\n\t// …\n\tjsRuntime: {\n\t\tplatform: \"node\",\n\t\tmoduleResolution: \"relative\", // only relative/absolute paths resolve from the VFS\n\t},\n};\n```\n\nWith `moduleResolution: \"relative\"`, `import \"./util.js\"` resolves from the\nvirtual filesystem, while a bare `import \"lodash\"` or a `node:*` builtin import\nfails. The default is full Node resolution, which is what `NodeRuntime` boots:\n\n| `moduleResolution` | `import \"pkg\"` | `import \"./x.js\"` | `node:*` |\n|---|:---:|:---:|:---:|\n| `node` (default) | ✅ | ✅ | ✅ |\n| `relative` | No | ✅ | No |\n| `none` | No | No | No |\n\n(`import \"pkg\"` = bare/`node_modules` specifier; `import \"./x.js\"` = relative or\nabsolute path; `node:*` follows the platform / `allowedBuiltins`.)\n\n- **`node`**: standard Node resolution: the `node_modules` ancestor walk, `exports`/`imports`/conditions, and `realpath`/symlink following.\n- **`relative`**: only relative and absolute paths resolve from the VFS; bare package specifiers and `node:*` builtins do not.\n- **`none`**: nothing resolves. Any `import` or `require` (including relative) fails. Produces a single self-contained entrypoint module, useful for locked-down evaluation of one script.\n\n## `allowedBuiltins`: restrict Node builtins (node platform only)\n\n`allowedBuiltins` narrows which `node:*` builtin modules guest code may import.\nSet it on the `jsRuntime` config to allow exactly the builtins a script needs:\n\n```ts\nconst config: CreateVmConfig = {\n\t// …\n\tjsRuntime: {\n\t\tplatform: \"node\",\n\t\tallowedBuiltins: [\"path\", \"fs\"], // only these resolve; everything else is denied\n\t},\n};\n```\n\nWith `allowedBuiltins: [\"path\", \"fs\"]`, `import(\"node:path\")` and\n`import(\"node:fs/promises\")` succeed (a root name like `fs` also covers its\nsubpaths), while `import(\"node:child_process\")` is rejected. Omitting\n`allowedBuiltins` keeps the engine default allow-list (what `NodeRuntime` uses);\n`[]` denies all builtins. It is only valid under `platform: \"node\"`; the other\nplatforms deny all `node:*` builtins regardless, and unknown builtin names are\nrejected.\n\n\u003CCard title=\"CreateVmConfig.jsRuntime full shape\" href=\"/docs/sdks/typescript\">\nThe complete jsRuntime config (platform, moduleResolution, allowedBuiltins) and the rest of CreateVmConfig.\n\u003C/Card>","src/content/docs/docs/features/runtime-platform.mdx","e51b3a7ef2390b71","docs/features/typescript",{"id":187,"data":189,"body":192,"filePath":193,"digest":194,"deferredRender":19},{"title":190,"description":191},"TypeScript","Compiling and type-checking TypeScript inside the sandbox.","`@secure-exec/typescript` runs the TypeScript compiler **inside the sandbox**. The `typescript` package is projected into the VM's virtual filesystem and every `createProgram`/`emit` call happens in the guest, so untrusted TypeScript never compiles or runs on the host.\n\n**Why compile in the sandbox:** type-checking attacker-controlled source is a **CPU and memory amplification** vector. A small malicious type (recursive conditional types, deeply nested generics) can make `tsc` spin for seconds or balloon its heap. Because the compiler runs in a disposable VM, the blow-up is contained by the sandbox boundary, and you can bound each run with a `timeout` instead of hanging or OOM-ing the host.\n\n## Install\n\n```bash\nnpm install @secure-exec/typescript secure-exec\n```\n\n## Compile and type-check a source string\n\n\u003CCodeSnippet file=\"examples/docs/feat-typescript/src/index.mts\" />\n\nPrints:\n\n```\nCompiled TypeScript to JavaScript inside the sandbox.\nexitCode: 0\nguest stdout:\nhello secure-exec #1\nhello secure-exec #2\nhello secure-exec #3\ntype check success: false\n error TS2322 (line 1): Type 'string' is not assignable to type 'number'.\nOK: TypeScript compiled and type-checked inside the sandbox.\n```\n\nEach diagnostic is structured (`code`, `category`, `message`, and a `line`/`column` when available), and `success` is `false` whenever any diagnostic is an error, so you can branch on results without parsing compiler text.\n\n## Compile a tsconfig.json project\n\nTo compile a whole project, seed a `tsconfig.json` and its sources with `files` (keyed by absolute guest path), then call `compileProject`. You can also project host directories into the VM with `mounts` instead of inlining them.\n\n```ts\nimport { createTypeScriptTools } from \"@secure-exec/typescript\";\n\nconst tools = createTypeScriptTools({\n files: {\n \"/root/tsconfig.json\": JSON.stringify({\n compilerOptions: { strict: true, target: \"ES2022\", module: \"ESNext\" },\n include: [\"src\"],\n }),\n \"/root/src/index.ts\": \"export const answer: number = 42;\\n\",\n },\n});\n\n// Compile every file the tsconfig includes, emitting into the VM filesystem.\nconst compiled = await tools.compileProject({ cwd: \"/root\" });\nconsole.log(\"project compiled:\", compiled.success);\nconsole.log(\"emitted:\", compiled.emittedFiles);\n\n// Or type-check only, without emitting any output.\nconst checked = await tools.typecheckProject({ cwd: \"/root\" });\nconsole.log(\"project type-checks:\", checked.success);\n```\n\n`compileProject` emits into the VM's virtual filesystem (`emittedFiles` lists the paths written). To pull that output back to the host, run the compile on a `NodeRuntime` directly and read the files with `rt.readFile`.\n\n## Bounding untrusted compiles\n\n`compileSource`/`typecheckSource` manage their own VM, so the compile is already contained. To put a wall-clock bound on running the *emitted* output (or your own compiler driver), run it on a `NodeRuntime` with a `timeout` or `AbortSignal`:\n\n```ts\nconst emitted = await tools.compileSource({ sourceText });\n\nconst rt = await NodeRuntime.create();\ntry {\n const out = await rt.exec(emitted.outputText ?? \"\", {\n timeout: 5_000,\n signal: AbortSignal.timeout(10_000),\n });\n console.log(out.exitCode);\n} finally {\n await rt.dispose();\n}\n```\n\nOn timeout or abort the guest process is killed inside the VM, so a runaway compile can never hang the host.","src/content/docs/docs/features/typescript.mdx","543aafc9ed303558","docs/sdks/rust",{"id":195,"data":197,"body":200,"filePath":201,"digest":202,"deferredRender":19},{"title":198,"description":199},"Rust SDK","Install the Secure Exec Rust client and find its generated docs.rs reference.","The `secure-exec-client` crate is the Rust SDK. It speaks the same sidecar wire protocol as the TypeScript client, so every capability reachable from `secure-exec` is also reachable from Rust through `SidecarProcess`.\n\n## Install\n\n```bash\ncargo add secure-exec-client\n```\n\nOr add it to `Cargo.toml`:\n\n```toml\n[dependencies]\nsecure-exec-client = \"*\"\n```\n\n## API reference\n\nThe full reference is generated with rustdoc and published to docs.rs. Use it as the source of truth for signatures and types.\n\n\u003CCard title=\"secure-exec-client on docs.rs\" href=\"https://docs.rs/secure-exec-client\">\n Generated rustdoc for the Rust client crate.\n\u003C/Card>","src/content/docs/docs/sdks/rust.mdx","114a9ad37e034994","docs/sdks/typescript",{"id":203,"data":205,"body":208,"filePath":209,"digest":210,"deferredRender":19},{"title":206,"description":207},"TypeScript SDK","Install the Secure Exec TypeScript SDK and find its generated API reference.","The `secure-exec` package is the TypeScript SDK. It exports `NodeRuntime`, the batteries-included entry point for booting a virtualized VM and running guest JavaScript, plus the types describing its options and results.\n\n## Install\n\n```bash\nnpm install secure-exec\n```\n\n```ts\nimport { NodeRuntime } from \"secure-exec\";\n\nconst rt = await NodeRuntime.create();\ntry {\n const { stdout } = await rt.exec(\"console.log('hi', 1 + 1)\");\n console.log(stdout);\n} finally {\n await rt.dispose();\n}\n```\n\n## API reference\n\nThe full type-level reference is generated from the source with TypeDoc and is the source of truth for every export, method, and option.\n\n\u003CCard title=\"TypeScript API Reference\" href=\"/api\">\n Generated TSDoc for the secure-exec package.\n\u003C/Card>","src/content/docs/docs/sdks/typescript.mdx","fa7261a95089afd2","docs/use-cases/ai-agent-code-exec",{"id":211,"data":213,"body":216,"filePath":217,"digest":218,"deferredRender":19},{"title":214,"description":215},"AI Agent Code Exec","Give AI agents a secure code-execution tool that runs untrusted code in a sandbox and returns structured results.","\u003CCard title=\"Example on GitHub\" href=\"https://github.com/rivet-dev/secure-exec/tree/main/examples/docs/uc-ai-agent-code-exec\">\n Full working example that runs untrusted code and captures its result.\n\u003C/Card>\n\nGive your agent a code-execution tool that runs untrusted, model-generated code in a fully virtualized VM. The agent writes code, it runs inside the kernel isolation boundary with no access to the host, and you get back its stdout and a structured return value.\n\n## Run untrusted JavaScript and capture a result\n\n`NodeRuntime.create()` boots a sandboxed VM. `rt.run()` executes the guest code and decodes whatever it passes to `globalThis.__return()`, while still capturing `stdout`, `stderr`, and `exitCode`. Use `rt.exec()` when you only need the captured output streams.\n\nThe guest code runs as a standard ES module (top-level `await` and `import` work), but it can only see the virtual filesystem and kernel-mediated syscalls, and it cannot reach the host machine.\n\n\u003CCodeSnippet file=\"examples/docs/uc-ai-agent-code-exec/src/index.mts\" />\n\n*[See Full Example](https://github.com/rivet-dev/secure-exec/tree/main/examples/docs/uc-ai-agent-code-exec)*\n\nRunning this prints the captured stdout and the decoded return value, and shows that the guest only ever sees the sandbox:\n\n```\nexitCode: 0\nstdout: computed 20 fibonacci numbers\nreturned value: {\"fibonacci\":[0,1,1,2,3,5,8,13,21,34,55,89,144,233,377,610,987,1597,2584,4181],\"sum\":10945}\n\nescape attempt exitCode: 0\nescape attempt stdout: guest hostname: secure-exec\n```\n\n## Wiring it into an agent tool\n\nA single `NodeRuntime` instance can run many programs. Each `run()` / `exec()` call executes a fresh guest process. To expose this as a tool to your agent framework, hold one runtime for the session and call `rt.run(code)` from the tool's handler, returning `{ stdout, value, exitCode }` to the model. Pass a `timeout` (in milliseconds) per call to bound runaway code, and call `rt.dispose()` when the session ends.\n\n## Sandboxing untrusted code\n\n`NodeRuntime.create()` denies network by default and allows the virtualized `fs`, `childProcess`, `process`, and `env` scopes; any `permissions` you pass merges over that default, so an omitted scope keeps its default rather than being denied. Pass a partial policy (for example `{ network: \"allow\" }` to opt into the network, or a rule set on `fs` to tighten filesystem access) to adjust individual scopes.\n\n```ts\nimport { NodeRuntime } from \"secure-exec\";\n\n// network is already denied by default; this opts it back in while the other\n// scopes keep their defaults.\nconst rt = await NodeRuntime.create({\n permissions: { network: \"allow\" },\n});\n```\n\n\u003CCard title=\"Permissions\" href=\"/docs/features/permissions\">\n The full policy model: scopes, rule sets, and how partial policies merge over the secure default.\n\u003C/Card>\n\nYou can also constrain the run with `env` and `cwd` on `NodeRuntime.create()`, and `env`, `cwd`, `stdin`, and `timeout` on each `run()` / `exec()` call.","src/content/docs/docs/use-cases/ai-agent-code-exec.mdx","faeb3cf719a59cdd","docs/use-cases/code-mode",{"id":219,"data":221,"body":224,"filePath":225,"digest":226,"deferredRender":19},{"title":222,"description":223},"Code Mode (MCP)","Give AI agents a single code-execution tool instead of individual MCP tools. The LLM writes code that chains binding calls, executed safely in Secure Exec.","\u003CCard title=\"Example on GitHub\" href=\"https://github.com/rivet-dev/secure-exec/tree/main/examples/docs/uc-code-mode\">\n Full working example: the LLM chains real host binding calls in one sandboxed run and returns a structured result.\n\u003C/Card>\n\nInstead of calling MCP tools one at a time, Code Mode lets the LLM write JavaScript that orchestrates everything in one go, run safely in a V8 sandbox by Secure Exec.\n\n\u003CTip>\n [MCP Toolkit](https://mcp-toolkit.nuxt.dev/advanced/code-mode) provides a premade Code Mode library powered by Secure Exec: `experimental_codeMode: true`. We recommend trying it first. The rest of this page covers how to implement Code Mode yourself.\n\u003C/Tip>\n\n## Why Code Mode\n\n- **[81% less token overhead](https://x.com/hugorcd/status/2034616192225407273)**: With 50 tools, replacing per-call tool descriptions with a single code-execution tool cuts tool description tokens by 81%\n- **Fewer round-trips**: Chain multiple tool calls, conditionals, and data transformations in a single execution\n- **Real control flow**: Loops, branching, and `Promise.all`, not a chain of isolated tool calls\n- **One structured result**: The LLM returns a single JSON value via `globalThis.__return()`, decoded on the host as `result.value`\n\n## How it works\n\n1. Register your host bindings on the host with `NodeRuntime.create({ bindings })`. Each becomes a named command inside the sandbox.\n2. Give the LLM one tool (\"execute code\") and feed its generated JavaScript to `rt.run()`.\n3. The generated code invokes your bindings by name. Each call round-trips out of the sandbox, runs the binding's host `handler`, and the handler's return value comes back to the guest.\n4. The guest hands a single structured result back to the host with `globalThis.__return(value)`, which `rt.run()` decodes as `result.value`.\n\nHost bindings are the heart of Code Mode. The handlers run on the host, never in the sandbox, so the guest gets controlled, named capabilities (the kind an AI agent calls as tools) without being granted the underlying access. Registering bindings auto-grants the `binding` permission scope; pass your own `permissions.binding` policy to gate individual bindings.\n\n## Register the host bindings\n\nEach binding has a `description`, a JSON Schema `inputSchema`, and a `handler`. The handler receives the parsed input and returns a JSON-serializable result.\n\n\u003CCodeSnippet file=\"examples/docs/uc-code-mode/src/index.mts\" region=\"bindings\" />\n\n## The agent's generated code\n\nThe agent then generates code like this (call it `llmGeneratedCode`). The guest calls each binding with the `callBinding(name, input)` global, which resolves with the host handler's return value. It chains three binding calls with real control flow (`Promise.all`, arithmetic, branching) in one execution, then returns a single structured result:\n\n\u003CCodeSnippet file=\"examples/docs/uc-code-mode/src/index.mts\" region=\"generated-code\" />\n\n## Run it and read the result\n\nRun the LLM's code in one sandboxed pass and read back the structured result:\n\n\u003CCodeSnippet file=\"examples/docs/uc-code-mode/src/index.mts\" region=\"run\" />\n\nThree tool calls, one sandbox execution, zero extra LLM round-trips. Running it prints:\n\n```text\nexitCode: 0\nstdout: chained 3 binding calls in one sandbox execution\nstructured result: {\n \"san_francisco\": {\n \"temp_f\": 61\n },\n \"tokyo\": {\n \"temp_f\": 75\n },\n \"difference\": {\n \"fahrenheit\": 14,\n \"celsius\": 7.777777777777778\n },\n \"warmer\": \"Tokyo\"\n}\n```\n\n## Further reading\n\n- [Complete Code Mode implementation guide](https://mcp-toolkit.nuxt.dev/advanced/code-mode): end-to-end Code Mode walkthrough using MCP Toolkit\n- [Cloudflare Code Mode blog post](https://blog.cloudflare.com/code-mode/)\n- [AI Agent Code Exec](/use-cases/ai-agent-code-exec) for simpler single-tool execution patterns","src/content/docs/docs/use-cases/code-mode.mdx","d847a401284c3433","docs/use-cases/dev-servers",{"id":227,"data":229,"body":232,"filePath":233,"digest":234,"deferredRender":19},{"title":230,"description":231},"Dev Servers","Run user-provided server-style code (HTTP servers, request handlers) inside a secure isolate.","\u003CCard title=\"Example on GitHub\" href=\"https://github.com/rivet-dev/secure-exec/tree/main/examples/docs/uc-dev-servers\">\n Full working example that boots a long-running HTTP server inside a sandboxed isolate and drives host requests into it.\n\u003C/Card>\n\nLet users run their own server-style code inside a sandboxed isolate. A guest program can boot a real `node:http` server, bind a loopback port owned by the kernel, and serve requests, all without touching the host machine.\n\nSecure Exec keeps a guest server running and forwards host requests into it. `spawn()` starts a long-running guest program and returns a process handle immediately, without waiting for it to exit. `fetch(port, { method, path, headers, body })` drives an HTTP request from the host into the guest server listening on that port, through the kernel socket table, and returns the response. The request and response never leave the VM, so this works even when guest network egress is denied.\n\n## Spawn a server and drive host requests into it\n\nThe guest boots an HTTP server on loopback and stays alive serving requests. The host spawns it, blocks on `waitForListener()` until the server is accepting connections, drives a request into it, then kills the process and waits for it to exit.\n\n```ts\nimport { NodeRuntime } from \"secure-exec\";\n\n// A user's \"dev server\": untrusted, long-running server-style code. It boots a\n// real node:http server and keeps serving until it is killed, all inside the\n// secure-exec VM with no access to the host machine.\nconst devServer = `\nimport http from \"node:http\";\n\n// Start the user's server, exactly as they wrote it.\nconst app = http.createServer((req, res) => {\n if (req.url === \"/health\") {\n res.writeHead(200, { \"content-type\": \"application/json\" });\n res.end(JSON.stringify({ ok: true }));\n return;\n }\n res.writeHead(200, { \"content-type\": \"text/plain\" });\n res.end(\"hello from the sandboxed dev server\");\n});\n\n// Listen on loopback inside the VM. The kernel owns this socket; it never\n// touches a real host port. The process stays alive serving requests until the\n// host kills it.\napp.listen(3000, \"127.0.0.1\", () => {\n console.log(\"server listening on 127.0.0.1:3000\");\n});\n`;\n\n// The guest binds a loopback port, so opt in to networking. NodeRuntime.create()\n// denies network by default; permissions merge over that secure default.\nconst runtime = await NodeRuntime.create({ permissions: { network: \"allow\" } });\n\ntry {\n\t// spawn() starts the server as a long-running guest process and returns a\n\t// handle immediately, without waiting for it to exit.\n\tconst server = await runtime.spawn(devServer, {\n\t\tonStdout: (chunk) => process.stdout.write(new TextDecoder().decode(chunk)),\n\t});\n\tconsole.log(\"spawned guest server, pid:\", server.pid);\n\n\ttry {\n\t\t// Block until the guest is actually accepting connections on the port,\n\t\t// then drive requests into it.\n\t\tawait runtime.waitForListener({ port: 3000 });\n\n\t\t// Drive a real host->guest request into the running server.\n\t\tconst health = await runtime.fetch(3000, { path: \"/health\" });\n\t\tconsole.log(\"health check ->\", health.status, JSON.stringify(health.body));\n\n\t\tconst res = await runtime.fetch(3000, { method: \"GET\", path: \"/\" });\n\t\tconsole.log(\"GET / ->\", res.status, JSON.stringify(res.body));\n\n\t\tconsole.log(\n\t\t\t\"RESULT \" + JSON.stringify({ status: res.status, body: res.body }),\n\t\t);\n\t} finally {\n\t\t// Tear the server down and wait for the guest process to exit.\n\t\tserver.kill();\n\t\tawait server.wait();\n\t\tconsole.log(\"server stopped\");\n\t}\n} finally {\n\t// Tear down the VM and release the sidecar.\n\tawait runtime.dispose();\n}\n```\n\n*[See Full Example](https://github.com/rivet-dev/secure-exec/tree/main/examples/docs/uc-dev-servers)*\n\nRunning it spawns the server, drives host requests into it, and tears it down:\n\n```\nspawned guest server, pid: 1000000\nserver listening on 127.0.0.1:3000\nhealth check -> 200 \"{\\\"ok\\\":true}\"\nGET / -> 200 \"hello from the sandboxed dev server\"\nRESULT {\"status\":200,\"body\":\"hello from the sandboxed dev server\"}\nserver stopped\n```\n\nThe guest owns the server process, the application code, and the loopback socket, while the host stays in control of the lifecycle through the process handle (`kill()`, `wait()`) and `dispose()`. The kernel mediates the socket, so the guest never binds a real host port.\n\nThis is useful for platforms that let users write and preview server-side code (live coding environments, serverless playgrounds, educational tools) without giving them access to the host machine.","src/content/docs/docs/use-cases/dev-servers.mdx","e131054aff3124f5","docs/use-cases/plugin-systems",{"id":235,"data":237,"body":240,"filePath":241,"digest":242,"deferredRender":19},{"title":238,"description":239},"Plugin Systems","Run user-authored plugins in isolation with explicit permissions.","Let users upload scripts or extensions without risking your host. The host controls what plugin code runs, what capabilities are available, and what structured data comes back.\n\n## Run a plugin in isolation\n\nThe host owns the plugin source and the input. Run the plugin with `run()` inside a sandboxed VM and get a structured value back: the guest calls `globalThis.__return(value)` with any JSON-serializable value, and that value is decoded on the host as `result.value`.\n\nThe plugin below gets filesystem access but no network access. The guest proves it cannot reach the network, then transforms the host-supplied input.\n\n\u003CCodeSnippet file=\"examples/docs/uc-plugin-systems/src/index.mts\" />\n\nThe plugin executes inside the kernel isolation boundary with only the capabilities you granted (network access is denied here), and the host gets back structured data via `__return()` rather than direct access to plugin internals.\n\nYou can combine this with [TypeScript](/docs/features/typescript) to type-check uploaded plugin code before enabling it.\n\n## Let plugins call curated host tools\n\nDenying a capability outright is one option, but most plugin systems need the opposite: the plugin must reach a few host capabilities, just not the raw underlying access. The canonical pattern is host tools. You register a narrow set of named tools whose handlers run on the host, and the untrusted plugin invokes them by name. The plugin never gets the database connection, the secret, or the network socket behind the tool; it only gets the curated surface you chose to expose.\n\nRegister host tools with the `tools` option on `create()` (or add them to a live runtime with `rt.registerTools()`). Each tool becomes a named command inside the VM, and the plugin invokes it with the `callHostTool(name, input)` global, which resolves with the host handler's return value.\n\n```ts Host Tools\nimport { NodeRuntime } from \"secure-exec\";\n\n// Register curated host tools. Their handlers run on the host, so the plugin\n// reaches these capabilities only through the tool surface you expose - never\n// the underlying database, secrets, or network behind them.\nconst runtime = await NodeRuntime.create({\n tools: {\n lookupUser: {\n description: \"Look up a user by id\",\n inputSchema: {\n type: \"object\",\n properties: { id: { type: \"string\" } },\n required: [\"id\"],\n },\n // Runs on the host. In a real system this would hit your database.\n handler: ({ id }: { id: string }) => ({\n id,\n name: id === \"u_1\" ? \"Ada Lovelace\" : \"Unknown\",\n }),\n },\n },\n});\n\ntry {\n // The untrusted plugin reaches the host capability only through callHostTool,\n // which resolves with the handler's return value.\n const { value } = await runtime.run\u003C{ id: string; name: string }>(`\n const user = await callHostTool(\"lookupUser\", { id: \"u_1\" });\n __return(user);\n `);\n\n console.log(\"looked-up user:\", value?.name);\n} finally {\n await runtime.dispose();\n}\n```\n\nThis is safe because the plugin reaches host capability only through the curated tool surface, never the underlying access behind it. The `tool` permission scope gates invocation: when you pass `tools` and set no `tool` policy, the scope is granted so the registered tools are invocable, but you can supply your own `permissions.tool` policy to gate individual tools.\n\nSee [Bindings](/docs/features/bindings) for the full guide, including input schemas, command aliases, and worked examples.","src/content/docs/docs/use-cases/plugin-systems.mdx","f3e6d58b861b8661"] \ No newline at end of file diff --git a/website/.astro/settings.json b/website/.astro/settings.json index b6a925cac..67ddaea2e 100644 --- a/website/.astro/settings.json +++ b/website/.astro/settings.json @@ -1,5 +1,5 @@ { "_variables": { - "lastUpdateCheck": 1781866330046 + "lastUpdateCheck": 1782614398215 } } \ No newline at end of file diff --git a/website/.gitignore b/website/.gitignore index 4617bd56e..f0fc6e857 100644 --- a/website/.gitignore +++ b/website/.gitignore @@ -1,3 +1,4 @@ # Auto-generated TypeDoc API reference (built by `pnpm run docs:gen:ts`, served at /api) public/api/ +vendor/ diff --git a/website/Dockerfile b/website/Dockerfile index 1d67f548f..1e7d4b559 100644 --- a/website/Dockerfile +++ b/website/Dockerfile @@ -6,24 +6,34 @@ # (@rivet-dev/docs-theme) is fetched from GitHub during install. FROM node:22-alpine AS build WORKDIR /app -# git is required for pnpm to resolve the github: docs-theme dependency. RUN apk add --no-cache git && npm install -g pnpm@9 -# Install deps first (cache layer) — from the website package, not the monorepo root. -COPY website/package.json ./ -RUN pnpm install +# Clone + build the shared docs theme at a pinned sha + generate the vendored +# @rivet-gg/icons dist. The icons generate needs a FontAwesome Pro token (set it +# as a Railway build variable; passed via --build-arg locally). It is only used +# in this discarded build stage — the final caddy image never contains it. +ARG DOCS_THEME_SHA=450c498555135098c6a927adfdf13458be9be22a +ARG FONTAWESOME_PACKAGE_TOKEN +RUN export FONTAWESOME_PACKAGE_TOKEN="$FONTAWESOME_PACKAGE_TOKEN" \ + && git clone https://github.com/rivet-dev/docs-theme.git /theme \ + && git -C /theme checkout "$DOCS_THEME_SHA" \ + && pnpm -C /theme install \ + && pnpm -C /theme/packages/theme/vendor/icons run gen:manifest \ + && pnpm -C /theme/packages/theme/vendor/icons run gen:vendor \ + && pnpm -C /theme/packages/theme build -# Copy the site source. +# Copy the site source + the SDK source the typedoc step reads from ../packages +# + the examples the embeds read from /examples. COPY website/ ./ - -# The docs:gen:ts (typedoc) step in the build reads the SDK source from -# ../packages, which lives outside website/. Bring just that package's source -# into the image at the path typedoc.json points at (../packages/core), plus the -# root tsconfig that package's tsconfig extends. COPY packages/core /packages/core COPY tsconfig.base.json /tsconfig.base.json +COPY examples /examples -RUN pnpm build +# Point the theme deps at the clone (committed deps are local for dev) and drop +# any injected meta, then install + build. +RUN node -e "const fs=require('fs'),p=require('./package.json'),d=p.dependencies;d['@rivet-dev/docs-theme']='file:/theme/packages/theme';d['@rivet-gg/components']='file:/theme/packages/theme/vendor/components';d['@rivet-gg/icons']='file:/theme/packages/theme/vendor/icons';delete p.dependenciesMeta;fs.writeFileSync('./package.json',JSON.stringify(p,null,2))" \ + && pnpm install \ + && pnpm build # Serve the static output. This is a static multi-page site (Astro/Starlight # emits /index.html), NOT an SPA — so resolve each page's index.html and diff --git a/website/astro.config.mjs b/website/astro.config.mjs index 0f926aa29..9e0ae3847 100644 --- a/website/astro.config.mjs +++ b/website/astro.config.mjs @@ -1,25 +1,113 @@ +import { fileURLToPath } from "node:url"; import { defineConfig } from "astro/config"; -import react from "@astrojs/react"; import tailwind from "@astrojs/tailwind"; import sitemap from "@astrojs/sitemap"; -import starlight from "@astrojs/starlight"; import { docsTheme } from "@rivet-dev/docs-theme"; import { siteConfig } from "./docs.config.mjs"; +// Build-foundation shim: the secure-exec docs CONTENT still imports +// `@astrojs/starlight/components`. Map that path onto a thin shim that +// re-exports the de-Starlighted theme's MDX primitives so content builds +// unchanged. Phase 2 rewrites the content to import the theme directly and +// drops this alias. +const starlightShim = fileURLToPath( + new URL("./src/lib/starlight-shim.jsx", import.meta.url), +); + // https://astro.build/config export default defineConfig({ site: "https://secureexec.dev", output: "static", integrations: [ - react(), - // Tailwind base styles are scoped to the landing page (which imports - // global.css itself); disabling global injection keeps them out of - // Starlight's docs pages. + // The shared Rivet docs framework (copied 1:1 from rivet.dev, no Starlight). + // docsTheme() provides react + mdx + the remark/rehype/Shiki pipeline + + // route generation + the virtual config. docs.config.mjs maps agentOS's + // identity/nav/sitemap onto it. + ...docsTheme(siteConfig), tailwind({ applyBaseStyles: false }), - // The shared Rivet docs theme — wraps Starlight entirely. All docs - // branding/chrome lives in @rivet-dev/docs-theme; docs.config.mjs maps - // Secure Exec's identity, nav, and pages onto it. - ...docsTheme(starlight, siteConfig), sitemap(), ], + vite: { + resolve: { + dedupe: ["react", "react-dom", "react/jsx-runtime", "react/jsx-dev-runtime"], + alias: { + "@astrojs/starlight/components": starlightShim, + }, + }, + optimizeDeps: { + // Force EVERY React island dependency into one optimize pass at + // startup. Otherwise Vite discovers a dep lazily on first request + // (seen: "new dependencies optimized: @rivet-gg/components ... + // reloading"), reloads mid-render, and react-dom ends up referencing a + // React instance whose hook dispatcher was reset → "Invalid hook call" + // → islands never hydrate. The split is in the optimizer, not on disk. + // Ref: withastro/astro#16766. Keep this list in sync with the libs the + // theme + vendored components actually import in island code. + include: [ + "react", + "react-dom", + "react-dom/client", + "react/jsx-runtime", + "react/jsx-dev-runtime", + "@rivet-gg/components", + "@rivet-gg/icons", + "framer-motion", + "lucide-react", + "posthog-js", + "posthog-js/react", + "@sentry/react", + "@headlessui/react", + "@floating-ui/react", + "react-hook-form", + "react-markdown", + "react-day-picker", + "react-resizable-panels", + // CJS island deps that fail ESM interop unless pre-bundled (the + // actual hydration blocker — "does not provide an export"). They're + // imported from INSIDE the theme package, so use Vite's + // `linked-pkg > nested-dep` syntax to force them through optimize. + "typesense", + "use-sync-external-store", + "use-sync-external-store/shim", + "use-sync-external-store/with-selector", + "@rivet-dev/docs-theme > typesense", + "@rivet-dev/docs-theme > use-sync-external-store", + "@rivet-dev/docs-theme > use-sync-external-store/with-selector", + "@rivet-gg/components > use-sync-external-store", + "@rivet-gg/components > use-sync-external-store/with-selector", + "@radix-ui/react-accordion", + "@radix-ui/react-avatar", + "@radix-ui/react-checkbox", + "@radix-ui/react-context-menu", + "@radix-ui/react-dialog", + "@radix-ui/react-dropdown-menu", + "@radix-ui/react-label", + "@radix-ui/react-popover", + "@radix-ui/react-progress", + "@radix-ui/react-radio-group", + "@radix-ui/react-scroll-area", + "@radix-ui/react-select", + "@radix-ui/react-separator", + "@radix-ui/react-slider", + "@radix-ui/react-slot", + "@radix-ui/react-switch", + "@radix-ui/react-tabs", + "@radix-ui/react-toggle", + "@radix-ui/react-toggle-group", + "@radix-ui/react-tooltip", + "@radix-ui/react-visually-hidden", + ], + }, + ssr: { + // The theme/components ship .tsx, so they must be bundled for SSR — + // but keep React external so the bundled theme and react-dom/server + // share one instance (clears the SSR-side "Invalid hook call" noise). + external: ["react", "react-dom", "react/jsx-runtime", "react/jsx-dev-runtime"], + noExternal: [ + "@rivet-dev/docs-theme", + "@rivet-gg/components", + "@rivet-gg/icons", + ], + }, + }, }); diff --git a/website/docs.config.mjs b/website/docs.config.mjs index dd4cf8492..9a0c34315 100644 --- a/website/docs.config.mjs +++ b/website/docs.config.mjs @@ -1,14 +1,42 @@ /** - * Secure Exec docs configuration — the only non-content surface consumed by - * @rivet-dev/docs-theme. Everything visual (theme, header chrome, sidebar - * icons, code blocks) lives in the package; this file maps Secure Exec's - * product identity, navigation, and pages onto it. + * Secure Exec docs configuration for @rivet-dev/docs-theme (the de-Starlighted, + * rivet-1:1 framework). Maps Secure Exec's product identity, navigation, and + * pages onto the theme's SiteConfig. * - * Sidebar leaves carry their icon via `attrs['data-icon']` (resolved against - * the theme's shared icon catalog), so the package never hardcodes routes. + * `sitemap` is the docs navigation tree: SiteTab[] where each tab carries a + * sidebar tree (pages + collapsible sections). Routes are /docs/* (file paths + * under src/content/docs). Top-level sections are non-collapsible labels; only + * nested page-groups collapse. Page items carry FontAwesome `IconDefinition`s + * for the sidebar icons. + * + * @type {import('@rivet-dev/docs-theme').SiteConfig} */ +import { + faCircleInfo, + faRocket, + faTerminal, + faFileCode, + faCode, + faBook, + faRobot, + faServer, + faPuzzlePiece, + faPlay, + faScroll, + faBolt, + faBox, + faCodeBranch, + faWrench, + faShieldHalved, + faFolder, + faNetworkWired, + faGauge, + faNodeJs, + faCodeCompare, + faCubes, + faLock, +} from "@rivet-gg/icons"; -/** @type {import('@rivet-dev/docs-theme').SiteConfig} */ export const siteConfig = { product: "Secure Exec", productLogo: "/secure-exec-logo-long-ink.svg", @@ -20,12 +48,27 @@ export const siteConfig = { // Local CSS appended after the shared theme stylesheet (so it overrides it). css: ["./src/styles/docs-overrides.css"], + // Docs pages have no top-nav links (Documentation/Changelog live on the + // marketing page's own Navigation). The header keeps logo + search + CTA. topNav: [], + // Single tab → the theme hides the secondary tab strip (only agentOS, with 2 + // tabs, shows it). Kept here so the docs section context still resolves. + tabs: [{ label: "Documentation", href: "/docs", match: "/docs" }], cta: { label: "Get Started", href: "/docs/quickstart" }, social: { discord: "https://rivet.dev/discord" }, analytics: { posthogKey: "phc_6kfTNEAVw7rn1LA51cO3D69FefbKupSWFaM7OUgEpEo" }, + // Hosted Typesense docs search (same cluster as rivet). The search-only key + // is safe to ship client-side; indexing uses the populate key (see scripts). + search: { + typesense: { + host: "3lsug6t152oxcjndp-1.a1.typesense.net", + searchApiKey: "3R49clF2Np3eoBoqd6PtYyEIqkA5nNVZ", + collectionName: "secureexec-docs", + }, + }, + landing: { title: "Documentation", subtitle: @@ -37,74 +80,83 @@ export const siteConfig = { ], }, - sidebar: [ - { slug: "docs", label: "Introduction", attrs: { "data-icon": "info" } }, + sitemap: [ { - label: "Getting Started", - items: [ - { slug: "docs/quickstart", attrs: { "data-icon": "rocket" } }, - { slug: "docs/crash-course", label: "Crash Course", attrs: { "data-icon": "terminal" } }, + title: "Documentation", + href: "/docs", + sidebar: [ + { title: "Introduction", href: "/docs", icon: faCircleInfo }, { - label: "SDKs", - collapsed: true, - items: [ - { slug: "docs/sdks/typescript", attrs: { "data-icon": "fileCode" } }, - { slug: "docs/sdks/rust", attrs: { "data-icon": "code" } }, - { label: "TypeScript API Reference", link: "/api", attrs: { "data-icon": "book", target: "_blank" } }, + title: "Getting Started", + pages: [ + { title: "Quickstart", href: "/docs/quickstart", icon: faRocket }, + { title: "Crash Course", href: "/docs/crash-course", icon: faTerminal }, + { + title: "SDKs", + icon: faCode, + collapsible: true, + pages: [ + { title: "TypeScript", href: "/docs/sdks/typescript", icon: faFileCode }, + { title: "Rust", href: "/docs/sdks/rust", icon: faCode }, + { title: "TypeScript API Reference", href: "/api", external: true, target: "_blank", icon: faBook }, + ], + }, + ], + }, + { + title: "Use Cases", + pages: [ + { title: "AI Agent Code Exec", href: "/docs/use-cases/ai-agent-code-exec", icon: faRobot }, + { title: "Code Mode", href: "/docs/use-cases/code-mode", icon: faCode }, + { title: "Dev Servers", href: "/docs/use-cases/dev-servers", icon: faServer }, + { title: "Plugin Systems", href: "/docs/use-cases/plugin-systems", icon: faPuzzlePiece }, + ], + }, + { + title: "Node.js Runtime", + pages: [ + { title: "Executing Code", href: "/docs/features/executing-code", icon: faPlay }, + { title: "Output Capture", href: "/docs/features/output-capture", icon: faScroll }, + { title: "Resident Runner", href: "/docs/features/resident-runner", icon: faBolt }, + { title: "TypeScript", href: "/docs/features/typescript", icon: faFileCode }, + { title: "NPM & Module Loading", href: "/docs/features/module-loading", icon: faBox }, + { title: "Runtime & Platform", href: "/docs/features/runtime-platform", icon: faCode }, + { title: "Child Processes", href: "/docs/features/child-processes", icon: faCodeBranch }, + { title: "Bindings", href: "/docs/features/bindings", icon: faWrench }, ], }, - ], - }, - { - label: "Use Cases", - items: [ - { slug: "docs/use-cases/ai-agent-code-exec", attrs: { "data-icon": "bot" } }, - { slug: "docs/use-cases/code-mode", attrs: { "data-icon": "code" } }, - { slug: "docs/use-cases/dev-servers", attrs: { "data-icon": "server" } }, - { slug: "docs/use-cases/plugin-systems", attrs: { "data-icon": "puzzle" } }, - ], - }, - { - label: "Node.js Runtime", - items: [ - { slug: "docs/features/executing-code", attrs: { "data-icon": "play" } }, - { slug: "docs/features/output-capture", attrs: { "data-icon": "scroll" } }, - { slug: "docs/features/resident-runner", attrs: { "data-icon": "zap" } }, - { slug: "docs/features/typescript", attrs: { "data-icon": "fileCode" } }, - { slug: "docs/features/module-loading", label: "NPM & Module Loading", attrs: { "data-icon": "package" } }, - { slug: "docs/features/runtime-platform", label: "Runtime & Platform", attrs: { "data-icon": "code" } }, - { slug: "docs/features/child-processes", attrs: { "data-icon": "split" } }, - { slug: "docs/features/bindings", attrs: { "data-icon": "wrench" } }, - ], - }, - { - label: "Virtual Machine", - items: [ - { slug: "docs/features/permissions", attrs: { "data-icon": "shield" } }, - { slug: "docs/features/filesystem", attrs: { "data-icon": "folder" } }, - { slug: "docs/features/networking", attrs: { "data-icon": "network" } }, - { slug: "docs/features/resource-limits", attrs: { "data-icon": "gauge" } }, - ], - }, - { - label: "Reference", - items: [ - { slug: "docs/nodejs-compatibility", attrs: { "data-icon": "nodejs" } }, - { slug: "docs/benchmarks", attrs: { "data-icon": "gauge" } }, { - label: "Comparison", - items: [ - { slug: "docs/comparison/sandbox", attrs: { "data-icon": "gitCompare" } }, - { slug: "docs/comparison/cloudflare-workers", attrs: { "data-icon": "gitCompare" } }, - { slug: "docs/comparison/quickjs", label: "vs QuickJS", attrs: { "data-icon": "gitCompare" } }, - { slug: "docs/comparison/isolated-vm", label: "vs isolated-vm", attrs: { "data-icon": "gitCompare" } }, + title: "Virtual Machine", + pages: [ + { title: "Permissions", href: "/docs/features/permissions", icon: faShieldHalved }, + { title: "Filesystem", href: "/docs/features/filesystem", icon: faFolder }, + { title: "Networking", href: "/docs/features/networking", icon: faNetworkWired }, + { title: "Resource Limits", href: "/docs/features/resource-limits", icon: faGauge }, ], }, { - label: "Advanced", - items: [ - { slug: "docs/architecture", attrs: { "data-icon": "blocks" } }, - { slug: "docs/security-model", attrs: { "data-icon": "lock" } }, + title: "Reference", + pages: [ + { title: "Node.js Compatibility", href: "/docs/nodejs-compatibility", icon: faNodeJs }, + { title: "Benchmarks", href: "/docs/benchmarks", icon: faGauge }, + { + title: "Comparison", + collapsible: true, + pages: [ + { title: "vs Sandbox", href: "/docs/comparison/sandbox", icon: faCodeCompare }, + { title: "vs Cloudflare Workers", href: "/docs/comparison/cloudflare-workers", icon: faCodeCompare }, + { title: "vs QuickJS", href: "/docs/comparison/quickjs", icon: faCodeCompare }, + { title: "vs isolated-vm", href: "/docs/comparison/isolated-vm", icon: faCodeCompare }, + ], + }, + { + title: "Advanced", + collapsible: true, + pages: [ + { title: "Architecture", href: "/docs/architecture", icon: faCubes }, + { title: "Security Model", href: "/docs/security-model", icon: faLock }, + ], + }, ], }, ], diff --git a/website/package.json b/website/package.json index 77d91d84f..5f445f2b1 100644 --- a/website/package.json +++ b/website/package.json @@ -10,13 +10,13 @@ "build": "pnpm run docs:gen:ts && astro build", "preview": "astro preview", "astro": "astro", - "docs:gen:ts": "typedoc" + "docs:gen:ts": "typedoc", + "docs:index": "node --input-type=module -e \"import('@rivet-dev/docs-theme/scripts/index-docs').then(m => m.indexDocs())\"" }, "dependencies": { - "@rivet-dev/docs-theme": "github:rivet-dev/docs-theme#v0.1.0", + "@rivet-dev/docs-theme": "file:vendor/theme", "@astrojs/react": "^4.2.0", "@astrojs/sitemap": "^3.2.0", - "@astrojs/starlight": "^0.36.0", "@astrojs/tailwind": "^6.0.0", "astro": "^5.18.2", "framer-motion": "^12.0.0", @@ -24,7 +24,9 @@ "react": "^19.0.0", "react-dom": "^19.0.0", "sharp": "^0.33.5", - "tailwindcss": "^3.4.0" + "tailwindcss": "^3.4.0", + "@rivet-gg/components": "file:vendor/theme/vendor/components", + "@rivet-gg/icons": "file:vendor/theme/vendor/icons" }, "devDependencies": { "@types/react": "^19.0.0", diff --git a/website/public/docs/docs.md b/website/public/docs/docs.md new file mode 100644 index 000000000..f5392d124 --- /dev/null +++ b/website/public/docs/docs.md @@ -0,0 +1,6 @@ +# Introduction + +'Secure Exec: a fully virtualized runtime for executing untrusted code with zero host escapes.' + +A lightweight library for secure Node.js execution. No containers, no VMs — just +npm-compatible sandboxing out of the box. \ No newline at end of file diff --git a/website/public/docs/docs/architecture.md b/website/public/docs/docs/architecture.md new file mode 100644 index 000000000..dd8dc0ca6 --- /dev/null +++ b/website/public/docs/docs/architecture.md @@ -0,0 +1,14 @@ +# Architecture + +A short overview of the Secure Exec architecture, with a link to the canonical agentOS architecture docs. + +Secure Exec runs untrusted guest code inside a fully virtualized VM whose kernel services every guest syscall. At a glance: + +- **Kernel-owned VM**: A kernel owns the virtual filesystem, process table, and socket table, plus pipes, PTYs, permission policy, and DNS. There is no real host filesystem, host socket, or host process available to the guest. +- **Guest runs in an executor**: Guest JavaScript runs in a V8 isolate and other guest code runs in a WASM executor, holding no real host capabilities of their own. +- **Sidecar mediates every syscall**: A trusted sidecar is the enforcement point. Every guest syscall flows through kernel-owned paths it controls, where policy and limits are checked. +- **Normal Linux semantics**: The VM presents POSIX-like behavior to guest programs, so normal tools run unmodified while staying fully virtualized. + +## Full reference + +The canonical, in-depth architecture reference, including packages, crates, trust boundaries, and syscall paths, is owned by agentOS. \ No newline at end of file diff --git a/website/public/docs/docs/benchmarks.md b/website/public/docs/docs/benchmarks.md new file mode 100644 index 000000000..8c0ca54f8 --- /dev/null +++ b/website/public/docs/docs/benchmarks.md @@ -0,0 +1,123 @@ +# Benchmarks + +Cold start, warm execution, and reuse fast-path measurements for the Secure Exec SDK. + +These numbers measure the public `secure-exec` SDK paths that consumers actually use. The cold start matrix (`packages/benchmarks/coldstart.bench.ts`) times the full journey from booting a runtime to running guest code, and compares three ways of provisioning a runtime against how much you can reuse. + +Numbers below are a full run from June 19, 2026 on the hardware listed under [Methodology](#methodology). They are indicative at this sample count (5 iterations + 1 warmup), not statistically tight. Reproduce them with the commands in [Running the benchmarks](#running-the-benchmarks). + +## Scenarios + +- **owned-sidecar**: `NodeRuntime.create()` boots a fresh sidecar process for each runtime. This is the default, fully isolated path (see [Process Isolation](/docs/architecture)). +- **shared-sidecar**: one sidecar process is created once and reused across many runtimes, instead of spawning a fresh sidecar per runtime. Sidecar setup is measured separately and excluded from cold start, so this isolates the per-runtime cost. (Sharing a sidecar is a reuse fast path: spawn one `Sidecar` and pass it to `NodeRuntime.create({ sidecar })`, instead of the default `NodeRuntime.create()` path that owns a fresh sidecar per runtime.) +- **resident-runner**: a shared sidecar plus a resident runner, so repeated small snippets reuse one live guest Node process instead of starting a new one each time. + +## Cold vs warm + +Each scenario reports two latencies: + +- **Cold**: provisioning the runtime and running the first guest snippet end to end. +- **Warm**: running a second snippet on the same runtime, after it is already up. + +A single sequential runtime (batch size 1) gives the cleanest picture: + +| Scenario | Cold mean | Cold p50 | Warm mean | Warm p50 | +| --- | ---: | ---: | ---: | ---: | +| owned-sidecar | 772.88ms | 771.96ms | 452.68ms | 452.37ms | +| shared-sidecar | 774.17ms | 774.50ms | 457.19ms | 452.75ms | +| resident-runner | 351.00ms | 349.56ms | 1.27ms | 1.27ms | + +The headline result is the resident runner: once the live guest process exists, a warm snippet runs in about **1.3ms**, roughly 350x faster than a warm execution that still has to stand up a guest process. Owned and shared sidecars cost about the same per runtime when run sequentially, because the sidecar process itself is cheap to spawn (around 3ms); sharing it mainly matters under concurrency. + +## Where the cold-start time goes + +Breaking down a single owned-sidecar cold start (batch 1, sequential, p50 per phase): + +| Phase | p50 | +| --- | ---: | +| sidecar_spawn | 2.78ms | +| session_open | 2.34ms | +| vm_create | 1.36ms | +| vm_configure | 0.17ms | +| runtime_mount_node | 2.71ms | +| runtime_mount_wasm | 172.95ms | +| runtime_create_total | 176.30ms | +| first_exec | 596.26ms | +| warm_exec | 452.37ms | + +Two phases dominate: mounting the WASM command set (about 173ms) and the first guest execution (about 596ms, which includes bringing up the guest Node runtime). Spawning the sidecar, opening a session, and creating the VM together cost only a few milliseconds. This is why the resident runner wins so decisively: it pays the first-exec cost once and then reuses the live process. + +## Concurrency + +The matrix also runs each scenario at larger batch sizes, both sequentially and concurrently (up to the host concurrency cap). Cold mean latency by batch size: + +| Scenario | Mode | b=1 | b=10 | b=50 | b=100 | b=200 | +| --- | --- | ---: | ---: | ---: | ---: | ---: | +| owned-sidecar | sequential | 772.88ms | 780.07ms | 777.49ms | 777.89ms | 778.28ms | +| owned-sidecar | concurrent | 776.22ms | 1000.39ms | 1041.81ms | 1041.19ms | 1044.03ms | +| shared-sidecar | sequential | 774.17ms | 627.58ms | 610.76ms | 619.24ms | 616.20ms | +| shared-sidecar | concurrent | 775.66ms | 3493.51ms | 3197.96ms | 3187.99ms | 3235.65ms | +| resident-runner | sequential | 351.00ms | 202.61ms | 187.92ms | 186.10ms | 189.76ms | +| resident-runner | concurrent | 347.91ms | 205.00ms | 187.45ms | 187.07ms | 191.33ms | + +Takeaways: + +- **owned-sidecar** holds flat when sequential. Run concurrently, per-runtime cold time rises to about 1040ms as many runtimes mount their WASM command sets at once and contend for CPU. Each runtime still has its own sidecar, so they make progress in parallel. +- **shared-sidecar** is efficient sequentially (around 610ms once the shared sidecar is warm) but degrades sharply under concurrency (3000ms or more), because one sidecar process serializes the heavy concurrent mount and first-exec work. Share a sidecar when work arrives sequentially or at low concurrency, not for bursty parallel fan-out. +- **resident-runner** improves with batch size as the one-time runner creation amortizes, settling around 187ms cold and about 1.3ms warm regardless of mode. + +## Choosing a strategy + +- Need strong isolation and unpredictable, bursty load: use **owned-sidecar** (the default). Each runtime is its own crash and resource domain. +- Running many short tasks back to back where a shared failure domain is acceptable: a **shared-sidecar** amortizes setup. +- Running the same kind of small snippet over and over (for example an evaluation loop): a **resident-runner** turns a roughly 450ms warm execution into a roughly 1.3ms one. + +See [Process Isolation](/docs/architecture) for what each of these shares and isolates. + +## Methodology + +```text +CPU: 12th Gen Intel(R) Core(TM) i7-12700KF +Cores: 20 | Max concurrency: 16 | Max live runtimes: 8 +RAM: 62.6 GB | Node: v24.13.0 +Iterations: 5 (+ 1 warmup) +Batch sizes: 1, 10, 50, 100, 200 +Scenarios: owned-sidecar, shared-sidecar, resident-runner +Sidecar: release build of secure-exec-sidecar +``` + +Cold start is wall time from the start of runtime provisioning through the first guest execution. Warm is a second execution on the already-running runtime. For shared-sidecar, the one-time sidecar setup (around 4ms to 5ms) is measured separately and excluded from the per-runtime cold number. Phase timings (`sidecar_spawn`, `session_open`, `vm_create`, `runtime_mount_wasm`, `first_exec`, and the resident-runner phases) are recorded in the machine-readable JSON output. + +## Running the benchmarks + +Build a release sidecar first for meaningful timings: + +```bash +cargo build --release -p secure-exec-sidecar +``` + +Run the full suite: + +```bash +pnpm --dir packages/benchmarks bench +``` + +Run only the cold start matrix: + +```bash +SECURE_EXEC_SIDECAR_BIN="$PWD/target/release/secure-exec-sidecar" \ + pnpm --silent --dir packages/benchmarks bench:coldstart \ + > packages/benchmarks/results/coldstart-local.json \ + 2> packages/benchmarks/results/coldstart-local.log +``` + +A quick smoke run keeps it to one iteration: + +```bash +BENCH_BATCH_SIZES=1 \ +BENCH_ITERATIONS=1 \ +BENCH_WARMUP=0 \ +BENCH_SCENARIOS=owned-sidecar,shared-sidecar,resident-runner \ +SECURE_EXEC_SIDECAR_BIN="$PWD/target/release/secure-exec-sidecar" \ + pnpm --silent --dir packages/benchmarks bench:coldstart +``` \ No newline at end of file diff --git a/website/public/docs/docs/comparison/cloudflare-workers.md b/website/public/docs/docs/comparison/cloudflare-workers.md new file mode 100644 index 000000000..cfd2db598 --- /dev/null +++ b/website/public/docs/docs/comparison/cloudflare-workers.md @@ -0,0 +1,101 @@ +# Secure Exec vs Cloudflare Workers + +How Secure Exec and Cloudflare Workers differ in isolation model, permissions, networking, and Node.js compatibility. + +Secure Exec and Cloudflare Workers both run untrusted JavaScript inside V8, but they solve different problems. Workers is a managed, multi-tenant edge platform: you deploy code and Cloudflare runs it for you across its network. Secure Exec is a library you embed in your own application to run guest code locally inside a fully virtualized VM that you control. This page focuses on how the two differ in isolation, permissions, networking, and Node.js surface. + +## At a glance + +| | Secure Exec | Cloudflare Workers | +| --- | --- | --- | +| **Form factor** | Library you embed (`secure-exec`), runs where your app runs | Managed edge platform you deploy to | +| **Isolation unit** | Per runtime: each `NodeRuntime.create()` is its own VM and OS process | Per Worker isolate, scheduled by Cloudflare | +| **Guest runtime** | V8 isolate inside a virtualized POSIX kernel (filesystem, processes, sockets, PTYs) | V8 isolate with the `workerd` runtime | +| **Permissions** | Deny-by-default capability policy you configure per runtime | Platform-managed; no per-call capability policy | +| **Subprocesses** | Real `node:child_process` against kernel-managed processes | Not available | +| **Filesystem** | Full virtualized filesystem per runtime | Limited in-memory `node:fs` surface, ephemeral | +| **You operate it** | Yes (your process, your machine) | No (Cloudflare operates it) | + +## Isolation model + +This is the most important difference, and the easiest one to misstate. + +Cloudflare Workers isolates code dynamically. Cloudflare's runtime schedules many Workers into a pool of V8 isolates and can move work between them, with platform-level mitigations (such as I/O-gated clock coarsening) layered on to defend against side-channel attacks across that shared infrastructure. + +Secure Exec isolates code statically, one boundary per runtime. Every `NodeRuntime.create()` boots a fully virtualized VM backed by its own sidecar process. Two runtimes share nothing: not the filesystem, not globals, not module state, and not crash fate. Secure Exec does not reassign guest code between processes at runtime, and it does not claim Cloudflare-style dynamic, cross-tenant isolate scheduling. You decide the blast radius by deciding how many runtimes to create and what to put in each one. + +Within a single runtime, every `exec()` or `run()` call runs in a fresh guest process, so in-memory state from one run does not leak into the next. + +The practical consequence: with Workers you trust Cloudflare's platform to keep tenants apart. With Secure Exec you get a hard, statically-defined boundary per runtime that you place yourself, which is well suited to running one tenant or one task per runtime and disposing it when finished. + +## Permissions + +Cloudflare Workers does not expose a per-invocation capability policy. What a Worker can reach is governed by its bindings and platform configuration. + +Secure Exec applies a deny-by-default capability policy per runtime. Network access is denied until you opt in; the virtualized filesystem, child-process, process, and env scopes are enabled so programs can run at all (the guest only ever sees the VM, never the real host). You tighten or widen any scope when you create the runtime. + +```ts +import { NodeRuntime } from "secure-exec"; + +// Default: no network access. Filesystem and processes are virtualized. +const sandboxed = await NodeRuntime.create(); + +// Opt into network access while keeping the other defaults. +const networked = await NodeRuntime.create({ + permissions: { network: "allow" }, +}); +``` + +The permission policy is merged over a secure default, so a partial policy like `{ network: "allow" }` works. See [Permissions](/docs/features/permissions) for rule-set syntax to gate individual scopes. + +## Networking + +Inside the VM, guest `fetch()` runs through undici in the V8 isolate and then through the kernel's socket table, gated by the network permission. Guest code can also bind ports inside the VM: Secure Exec exposes `findListener()` and `waitForListener()` so the host can detect when a guest process starts listening (for example, to wait for an in-VM HTTP server before sending it a request). + +From the host side, `rt.fetch(port, input)` drives an HTTP request into a guest server listening inside the VM and reads the response back. The request never leaves the VM (it connects to the guest's loopback listener through the kernel socket table), so it works even when guest network egress is denied. + +Cloudflare Workers provides outbound `fetch()` and a Sockets API for outbound TCP/TLS, but a Worker does not listen on a port the way a normal server does; it responds to incoming requests routed by the platform. + +```ts +import { NodeRuntime } from "secure-exec"; + +const rt = await NodeRuntime.create(); +try { + // Start a long-running guest HTTP server and get a live handle back. + const server = await rt.spawn(` + import http from "node:http"; + http.createServer((_req, res) => res.end("ok")).listen(3000); + `); + + // Block until the listener is up, then drive a request into it from the host. + await rt.waitForListener({ port: 3000 }); + const res = await rt.fetch(3000, { path: "/" }); + console.log(res.status, res.body); // 200 ok + + server.kill(); + await server.wait(); +} finally { + await rt.dispose(); +} +``` + +## Subprocesses and the POSIX surface + +Secure Exec presents a virtualized POSIX environment. Guest code can use `node:child_process` to spawn commands that exist inside the VM (such as `sh` and the mounted coreutils), and every child is a kernel-managed process, never a real host process. The host can also start a long-running guest program and drive it with `rt.spawn()`. + +Cloudflare Workers has no subprocess model. There is no `child_process`, no process table, and no shell. + +## Node.js compatibility + +Both runtimes aim to present Node.js semantics on top of V8, and both implement a large subset of the Node.js standard library. The character of the gaps differs: + +- **Secure Exec** is backed by a real virtualized kernel, so capabilities that need an OS, a full filesystem, real child processes, sockets that listen, and a process table, are first-class. Pure-JS builtins are provided through `node-stdlib-browser`, and kernel-backed modules (such as `fs`, `net`, `child_process`, `dns`, `http`, `os`) are wired through the bridge to the kernel. +- **Cloudflare Workers** provides Node.js compatibility through the `nodejs_compat` flag on top of `workerd`. Its filesystem is a limited in-memory surface, there is no subprocess support, and listening servers are replaced by the request/response handler model. In exchange it ships a comprehensive native `node:crypto` and Web Crypto surface and platform-native logging. + +Module support evolves on both sides. Treat the points above as the shape of the difference (kernel-backed POSIX vs managed edge isolate), not a frozen feature matrix. Verify a specific module against the current behavior of whichever runtime you target. + +## When to choose which + +Choose **Cloudflare Workers** when you want a managed, globally distributed platform to deploy your own trusted code to, with the operations handled for you. + +Choose **Secure Exec** when you need to run untrusted or AI-generated code inside your own application with a hard, self-placed isolation boundary, a real virtualized filesystem and process model, and a capability policy you control. One runtime per tenant or per task gives you a clean blast radius you can dispose on demand. \ No newline at end of file diff --git a/website/public/docs/docs/comparison/isolated-vm.md b/website/public/docs/docs/comparison/isolated-vm.md new file mode 100644 index 000000000..9abfcfd26 --- /dev/null +++ b/website/public/docs/docs/comparison/isolated-vm.md @@ -0,0 +1,87 @@ +# Secure Exec vs isolated-vm + +How Secure Exec and isolated-vm differ in isolation surface, security confinement, performance, and developer experience. + +Both Secure Exec and isolated-vm run untrusted JavaScript inside V8 isolates, but they operate at different layers. isolated-vm is a low-level npm library that exposes a bare V8 isolate with manual value marshaling and no system surface. Secure Exec wraps V8 isolates in a full virtualized kernel: a POSIX-like VFS, process table, socket table, permission policy, and resource limits. This page focuses on the security and performance characteristics of that core runtime layer. + +## At a glance + +| | Secure Exec | isolated-vm | +| --- | --- | --- | +| **Layer** | Full virtualized runtime around V8 isolates | Bare V8 isolate primitive | +| **System surface** | Virtualized filesystem, processes, sockets, PTYs, DNS | None (you build any surface yourself) | +| **Host and guest data** | Normal Node/POSIX I/O through the kernel | Manual `Reference`/`Copy`/`ExternalCopy` marshaling | +| **Permission model** | Deny-by-default capability policy per runtime | None (whatever you expose is reachable) | +| **Network egress** | Mediated by the kernel socket table, gated by policy | None by default; any bridge you add is unmediated | +| **Resource limits** | Per-VM CPU, memory, and other caps | Memory limit and timeout per isolate | +| **npm / Node compat** | Real npm packages run unmodified | None (no module system, no `node:` builtins) | + +## Isolation boundary + +The core difference is how much exists inside the boundary. + +- **isolated-vm** gives you a raw V8 isolate and nothing else. There is no filesystem, no network, no process model, and no globals beyond the ECMAScript spec. Anything the guest can reach, you have to inject yourself across the host/guest boundary by hand. +- **Secure Exec** boots a fully virtualized VM per runtime. The guest sees a POSIX-like filesystem, a process table, sockets, pipes, PTYs, and DNS, all backed by a kernel that the guest can never escape. Every guest syscall is routed through kernel-owned paths. + +The trade-off: isolated-vm is a primitive you assemble a sandbox out of. Secure Exec is the assembled sandbox. + +## Security + +A bare V8 isolate confines memory and CPU, but it confines nothing else, because there is nothing else inside it. The security of an isolated-vm deployment is entirely a property of the bridge code you write around it. + +- **What isolated-vm confines**: heap memory (per-isolate limit) and execution time (per-call timeout). It cannot leak host memory directly because the guest has no references it was not given. +- **What you must build yourself**: every capability the guest needs (file access, network, subprocesses) is a function you expose across the boundary. Each exposed function is attack surface, and each is unmediated unless you add your own checks. +- **What Secure Exec confines**: in addition to memory and time, it enforces a deny-by-default capability policy over filesystem, network, child-process, process, and env scopes. A denied operation fails with `EACCES`. +- **Egress control**: guest `fetch()`, `node:http`, and raw sockets flow through the kernel socket table, so outbound traffic can be allowed, denied, or rule-matched. With isolated-vm there is no networking until you build it, and once built it is not policed. + +With isolated-vm, a mistake in your marshaling layer (handing the guest a live host `Reference`, or an injected function that does unchecked I/O) is a sandbox escape. Secure Exec moves that boundary into a kernel so the surface the guest sees is virtualized rather than hand-wired per project. + +```ts +import { NodeRuntime } from "secure-exec"; + +// Deny-by-default: no network, filesystem and processes are virtualized. +const rt = await NodeRuntime.create(); + +// Opt into network egress; it is still mediated by the kernel socket table. +const networked = await NodeRuntime.create({ + permissions: { network: "allow" }, +}); +``` + +## Performance + +Both runtimes execute guest code in a V8 isolate, so raw JavaScript throughput is comparable. The cost differences come from what surrounds the isolate. + +- **isolated-vm** is the thinner layer: creating an isolate is cheap, and the dominant per-call cost is marshaling values across the host/guest boundary, which is explicit and pay-as-you-go. +- **Secure Exec** adds syscall virtualization. Guest I/O (files, sockets, processes) is routed through the kernel, so operations that touch the system carry virtualization overhead that a bare isolate does not. Pure compute that never makes a syscall runs at isolate speed. +- **Startup**: Secure Exec boots a virtualized VM per runtime, which is heavier than spinning up a bare isolate, but it is far lighter than a container or microVM. Reusing a live guest process drives warm execution into the low-millisecond range. See [Benchmarks](/docs/benchmarks) for measured numbers. + +The summary: isolated-vm has lower overhead because it does less; Secure Exec spends that overhead on a real system surface and enforcement you would otherwise build and pay for yourself. + +## Developer experience + +This is where the two diverge most for everyday use. + +- **isolated-vm**: you write to the isolate API directly. There is no module loader, no `node:` builtins, and no normal I/O. Passing data in or out means `Reference`, `Copy`, or `ExternalCopy`, and any capability is a function you wrap and inject. Running an existing npm package is not a goal of the library. +- **Secure Exec**: the guest sees normal Linux and Node semantics. Real npm packages run unmodified, resolved over a faithfully mounted `node_modules`, and kernel-backed modules (`fs`, `net`, `child_process`, `dns`, `http`, `os`) work as they would on a real machine. + +```ts +import { NodeRuntime } from "secure-exec"; + +const rt = await NodeRuntime.create(); +try { + const result = await rt.run(` + __return(40 + 2); + `); + console.log(result.value); // 42 +} finally { + await rt.dispose(); +} +``` + +## When to choose which + +| Choose | When | +| --- | --- | +| **isolated-vm** | You want a minimal V8 isolate primitive and intend to design and own the entire sandbox surface, capability injection, and enforcement yourself. | +| **Secure Exec** | You want to run untrusted or AI-generated code with a virtualized filesystem, process model, and networking, plus a deny-by-default permission policy and resource limits, without hand-building the sandbox. | \ No newline at end of file diff --git a/website/public/docs/docs/comparison/quickjs.md b/website/public/docs/docs/comparison/quickjs.md new file mode 100644 index 000000000..17fe60a30 --- /dev/null +++ b/website/public/docs/docs/comparison/quickjs.md @@ -0,0 +1,52 @@ +# Secure Exec vs QuickJS + +How Secure Exec and QuickJS differ in isolation model, performance, language coverage, and system surface. + +Secure Exec and QuickJS both run guest JavaScript, but they sit at different layers. QuickJS is a small, embeddable JavaScript engine: you link it into a host process and call its C API. Secure Exec is a full virtualized runtime built on V8, with a kernel, virtual filesystem, and capability policy around the engine. This page focuses on the security and performance characteristics of the core runtime layer. + +## At a glance + +| | Secure Exec | QuickJS | +| --- | --- | --- | +| **Engine** | V8 isolate (JIT) | QuickJS bytecode interpreter | +| **Isolation** | Virtualized VM in a dedicated sidecar process | Interpreter embedded in your host process | +| **Performance** | JIT-compiled, high throughput | Interpreted, smaller working set | +| **Language** | Full modern ECMAScript | Mostly ES2023, smaller engine | +| **Node/npm** | Real npm packages and Node-compatible builtins | None built in | +| **System surface** | Kernel: filesystem, processes, sockets, PTYs | None (host C bindings only) | + +## Isolation model + +This is the most important difference. + +- **QuickJS** is an interpreter you embed directly in your host process. Guest code shares the host's address space, and anything the guest can reach is whatever your C bindings expose. There is no process boundary between guest and host by default, so isolation is entirely your responsibility to build and audit. +- **Secure Exec** runs guest code in a V8 isolate inside a separate sidecar process, behind a virtualized POSIX kernel. Guest code never calls real Node.js builtins, never opens a real host socket, and never touches the real disk. Every syscall is routed through the kernel and checked against a deny-by-default permission policy. + +The practical consequence: with QuickJS you own the entire sandbox, including the boundary, the permission checks, and the host-bindings audit surface. With Secure Exec the boundary, the kernel, and the policy enforcement are provided and run out-of-process. + +## Performance + +The engines optimize for different things. + +- **V8 (Secure Exec)** JIT-compiles hot code to native machine code, so sustained throughput on compute-heavy guest code is far higher. The trade-off is a larger engine and a heavier per-isolate baseline. +- **QuickJS** compiles to bytecode and interprets it. It has a very small footprint and fast startup for a single embedded instance, but interpreted execution is slower on throughput-bound work. + +For Secure Exec, cold start is dominated by bringing up the guest runtime rather than provisioning infrastructure, and reusing a live guest process drives warm execution into the low-millisecond range. + +Treat these as the shape of the difference (JIT throughput vs interpreter footprint), not fixed numbers. See [Benchmarks](/docs/benchmarks) for measured cold-start, warm, and reuse numbers and the methodology behind them. + +## Language and ecosystem coverage + +- **Secure Exec** runs full modern ECMAScript on V8, the same engine as Node.js and Chrome, so language features land as V8 ships them. Real npm packages run unmodified inside the VM, resolved over a faithfully mounted `node_modules` like a real filesystem, and Node-compatible builtins are wired through the kernel. +- **QuickJS** implements most of the ECMAScript specification in a compact engine, but it tracks the spec on its own cadence and lags V8 on newer features and edge cases. It ships no Node.js standard library and no npm resolution; any package or builtin support is something you bind in yourself. + +## System surface + +- **Secure Exec** presents a virtualized POSIX environment to guest code: a per-runtime virtual filesystem, a kernel-managed process table (with `node:child_process`), a socket table for networking, pipes, and PTYs. Guest `fetch()`, `node:http`, and raw sockets all flow through the kernel and the permission policy. +- **QuickJS** has none of this built in. The bare engine exposes only ECMAScript globals; there is no filesystem, no process model, no networking, and no shell unless your host code adds C bindings for them. Every capability the guest needs is host surface you write and must secure. + +## When to choose which + +Choose **QuickJS** when you need the smallest possible embeddable engine, you are running short, self-contained scripts with no system needs, and you are prepared to build and audit any sandbox boundary and host bindings yourself. + +Choose **Secure Exec** when you need full ECMAScript and npm compatibility, JIT throughput, and a ready-made isolation boundary with a kernel-backed filesystem, process model, networking, and a deny-by-default capability policy you control. \ No newline at end of file diff --git a/website/public/docs/docs/comparison/sandbox.md b/website/public/docs/docs/comparison/sandbox.md new file mode 100644 index 000000000..665b0b989 --- /dev/null +++ b/website/public/docs/docs/comparison/sandbox.md @@ -0,0 +1,86 @@ +# Secure Exec vs Container Sandbox + +When to use a container sandbox versus Secure Exec for running untrusted code. + +Secure Exec and container sandboxes both run untrusted code in isolation, but they sit at different points on the weight-versus-flexibility curve. Picking the right one depends on what you need to run. + +**Secure Exec** boots a fully virtualized VM for each runtime and runs guest JavaScript in a V8 isolate inside a dedicated sidecar process. There is no Docker daemon, no orchestrator, and no vendor account: you `npm install` the package and call `NodeRuntime.create()`. It is built for lightweight, high-fanout code execution like AI tool calls, user scripts, and plugins, where you want granular permissions and a small footprint. + +**Container sandboxes** (e2b, Daytona, Modal, Cloudflare Containers, and similar) spin up a full OS image with system packages, a writable disk, and the ability to run arbitrary binaries. They are built for heavyweight workloads that need a complete environment: coding agents, long-lived dev sessions, or anything that shells out to native tools. + +## How isolation works + +The biggest difference is what the isolation boundary is made of. + +- **Secure Exec** runs guest code in a V8 isolate hosted by its own sidecar process. Every `NodeRuntime.create()` is a separate VM with its own virtual filesystem, process table, network policy, and crash domain. Guest code never calls real Node.js builtins, never opens a real host socket, and never touches the real disk. Every syscall is routed through the kernel. See [Process Isolation](/docs/architecture). +- **Container sandboxes** isolate with OS-level primitives (namespaces, cgroups, or a microVM). The guest runs a real kernel and a real filesystem, so it can do anything a Linux process can, constrained by the container's configuration. + +Secure Exec presents normal Linux semantics to the code it runs (a POSIX-like virtual filesystem, processes, pipes, PTYs, sockets) without granting access to the host that backs them. + +## Comparison + +| Dimension | Secure Exec | Container Sandbox | +| --- | --- | --- | +| Isolation boundary | Virtualized VM + V8 isolate in a sidecar process | OS container or microVM | +| Setup | `npm install secure-exec` | Vendor account or Docker host | +| Hardware | Runs on your infrastructure | Often vendor-hosted | +| Filesystem | Virtual, in-memory, per runtime | Full OS filesystem | +| Network | Denied by default, opt-in per runtime | Full, or firewall rules | +| Permissions | Per-scope policy (fs, network, childProcess, process, env, tool) | Coarse, container-level | +| Languages | JavaScript and TypeScript (Node-compatible) | Any language the image supports | +| Arbitrary binaries | No (guest binaries run through the VM, not the host) | Yes | +| Crash domain | One process per runtime | One container per sandbox | + +## What Secure Exec gives you + +These capabilities are the reason to reach for Secure Exec over a container when the workload fits in a Node-compatible runtime: + +- **Deny-by-default permissions.** Network egress is blocked until you opt in, and every guest syscall is checked against a per-scope policy before any host resource is touched. A denied operation fails with `EACCES`. See [Permissions](/docs/features/permissions). +- **Virtual filesystem.** Each runtime gets its own in-memory filesystem. Guest reads and writes never reach the host disk, and two runtimes writing the same path do not collide. See [Filesystem](/docs/features/filesystem). +- **Mediated networking.** Guest `fetch()`, `node:http`, and raw sockets all flow through the kernel socket table, so you can allow, deny, or rule-match outbound traffic. See [Networking](/docs/features/networking). +- **Process-level isolation.** Each runtime is its own VM and its own crash domain, and each `exec()` / `run()` starts a fresh guest process so in-memory state never leaks between runs. See [Process Isolation](/docs/architecture). +- **npm compatibility.** Real npm packages run unmodified inside the VM, resolved over a faithfully mounted `node_modules` like a real filesystem. See [Module Loading](/docs/features/module-loading). + +## When to use each + +### Use Secure Exec when + +- You are running **JavaScript or TypeScript** (AI tool calls, user scripts, plugins, evaluation loops). +- You want **no vendor dependency** and to run on your own infrastructure. +- You need **granular, deny-by-default permissions** over the filesystem, network, and child processes. +- You are running **many short tasks** and want a small per-task footprint. + +### Use a container sandbox when + +- You need a **full OS environment**: system packages, arbitrary binaries, or languages beyond a Node-compatible runtime. +- You need a **persistent, long-lived** environment such as a multi-hour dev session. +- The workload genuinely needs a real kernel and a real disk. + +**Need a full sandboxed operating system?** + +If your workload needs complete sandbox environments (for example, running coding agents like Claude Code, Codex, or Amp), the [Sandbox Agent SDK](https://sandboxagent.dev/) provides a unified interface for driving agents inside sandboxes. + +## A minimal example + +Booting a Secure Exec runtime takes no infrastructure beyond the installed package. The runtime owns its VM until you dispose it: + +```ts +import { NodeRuntime } from "secure-exec"; + +// Network is denied by default; the guest runs in its own virtualized VM. +const rt = await NodeRuntime.create(); +try { + const result = await rt.run(` + __return(40 + 2); + `); + console.log(result.value); // 42 +} finally { + await rt.dispose(); +} +``` + +There is no container to build, no image to pull, and no daemon to keep running. + +## Performance + +Because there is no container image or microVM to boot, a Secure Exec runtime starts in a fraction of the time a container takes, and the dominant cost is bringing up the guest runtime rather than provisioning infrastructure. For workloads that run the same kind of snippet repeatedly, reusing a live guest process drives warm execution into the low-millisecond range. See [Benchmarks](/docs/benchmarks) for measured cold-start, warm, and reuse numbers and the methodology behind them. \ No newline at end of file diff --git a/website/public/docs/docs/crash-course.md b/website/public/docs/docs/crash-course.md new file mode 100644 index 000000000..17bc3a71e --- /dev/null +++ b/website/public/docs/docs/crash-course.md @@ -0,0 +1,109 @@ +# Crash Course + +A fast tour of Secure Exec: install, run code, capture output, and the core SDK concepts. + +This is a fast, guided walk through the essentials: install the SDK, boot a +runtime, run guest code, and capture its output. By the end you will understand +the core loop and know where to go for more. + +`NodeRuntime` is the entry point: it boots a virtualized VM and runs guest JavaScript end to end, secure by default (no host filesystem, network, or process access until you allow it) and with every `create()` option optional so you can start with zero setup. + +For exact signatures and option shapes, see the +[TypeScript SDK reference](/docs/sdks/typescript). + +## Install + +```bash +npm install secure-exec +``` + +```bash +bun add secure-exec +``` + +```bash +pnpm add secure-exec +``` + +```bash +yarn add secure-exec +``` + +## Your first run + +The core loop is always the same: create a runtime, run code, dispose it. + +```ts +import { NodeRuntime } from "secure-exec"; + +const rt = await NodeRuntime.create(); +try { + const { stdout } = await rt.exec("console.log('hi', 1 + 1)"); + console.log(stdout); // "hi 2\n" +} finally { + await rt.dispose(); +} +``` + +- **`NodeRuntime.create()`**: boots a fresh VM. Reuse one runtime across many runs. +- **`rt.exec(code)`**: runs guest code as an ES module. +- **`rt.dispose()`**: releases the VM and its sidecar. Always call it when done. + +*[See Full Example](https://github.com/rivet-dev/secure-exec/tree/main/examples/docs/sdk-overview)* + +## Capture output + +`exec()` returns the streams and exit code from the run. + +```ts +const { stdout, stderr, exitCode } = await rt.exec(` + console.log("to stdout"); + console.error("to stderr"); +`); +console.log(exitCode); // 0 +``` + +`exitCode` is `0` on a clean exit and non-zero if the guest threw or was killed. + +Read more about [Output Capture](/docs/features/output-capture). + +## Return a value + +Use `run()` when you want a typed value back instead of parsing stdout. The +guest returns it with `globalThis.__return(value)`. + +```ts +const { value } = await rt.run<{ sum: number }>(` + globalThis.__return({ sum: 2 + 40 }); +`); +console.log(value?.sum); // 42 +``` + +Read more about [Executing Code](/docs/features/executing-code). + +## Set a timeout + +Pass a `timeout` so a runaway guest cannot run forever. The VM kills the process +when the budget elapses. + +```ts +const result = await rt.exec(`while (true) {}`, { timeout: 1000 }); +console.log(result.exitCode); // non-zero: the guest was killed +``` + +Read more about [Resource Limits](/docs/features/resource-limits). + +## Where to go next + +You now know the core loop. Each feature builds on it: + +- **[Executing Code](/docs/features/executing-code)**: `exec`, `run`, modules, and inputs. +- **[Child Processes](/docs/features/child-processes)**: `spawn()` for long-running guest programs. +- **[Resident Runner](/docs/features/resident-runner)**: keep a guest process alive for fast repeated runs. +- **[Filesystem](/docs/features/filesystem)**: read, write, and seed the virtualized VFS. +- **[NPM & Module Loading](/docs/features/module-loading)**: resolve real npm packages inside the VM. +- **[Networking](/docs/features/networking)**: guest `fetch`, sockets, and driving HTTP into a guest server. +- **[Bindings](/docs/features/bindings)**: expose curated host functions to guest code. +- **[Permissions](/docs/features/permissions)**: grant network and other access over the secure default. +- **[Runtime & Platform](/docs/features/runtime-platform)**: shape the env, cwd, and platform the guest sees. +- **[TypeScript](/docs/features/typescript)**: compile and type-check inside the sandbox. \ No newline at end of file diff --git a/website/public/docs/docs/features/bindings.md b/website/public/docs/docs/features/bindings.md new file mode 100644 index 000000000..aa608eb90 --- /dev/null +++ b/website/public/docs/docs/features/bindings.md @@ -0,0 +1,175 @@ +# Bindings + +Give sandboxed guest code a narrow, curated set of host-backed capabilities. + +Bindings are host-side functions the guest invokes by name: + +- **Where the handler runs**: on the **host**, never inside the guest sandbox. +- **Return value**: round-trips back to the guest as JSON. +- **Why use them**: hand untrusted guest code a narrow, curated capability surface (the kind an AI agent calls as tools) without granting it the underlying access. + +## Registering tools at boot + +Pass `tools` to `NodeRuntime.create()`. Each key becomes a named command the guest can run. + +```ts +import { NodeRuntime } from "secure-exec"; + +const rt = await NodeRuntime.create({ + tools: { + "get-weather": { + description: "Look up the current temperature for a city", + inputSchema: { + type: "object", + properties: { city: { type: "string" } }, + required: ["city"], + }, + // Runs on the HOST. The return value is delivered back to the guest. + handler: ({ city }: { city: string }) => { + const table: Record = { + "San Francisco": { temp_f: 61 }, + Tokyo: { temp_f: 75 }, + }; + return table[city] ?? { temp_f: null }; + }, + }, + }, +}); +``` + +*[See Full Example](https://github.com/rivet-dev/secure-exec/tree/main/examples/docs/uc-code-mode)* + +## Registering tools on a live runtime + +You can also add tools after the VM is running with `rt.registerTools({...})`. This is the same capability as the `tools` create option, exposed for a running runtime. + +```ts +await rt.registerTools({ + reverse: { + description: "Reverse a string", + inputSchema: { + type: "object", + properties: { text: { type: "string" } }, + required: ["text"], + }, + handler: ({ text }: { text: string }) => ({ result: [...text].reverse().join("") }), + }, +}); +``` + +When you register tools on a live runtime, make sure the `tool` permission scope is granted (see below) so the tools are invocable. + +## The tool definition + +A `HostToolDefinition` has these fields: + +- **`description`** (required): human-readable summary of what the tool does. +- **`inputSchema`** (required): JSON Schema describing the input. +- **`handler(input)`** (required): the function that runs on the host, returning a JSON-serializable value. +- **`timeoutMs`** (optional): abort the host handler after this many milliseconds. +- **`examples`** (optional): worked examples (each `{ description, input }`) shown alongside the tool. +- **`commandAliases`** (optional): extra command names the guest may use, beyond the registered key. + +```ts +const rt = await NodeRuntime.create({ + tools: { + lookupWeather: { + description: "Look up the current weather for a city", + inputSchema: { + type: "object", + properties: { city: { type: "string" } }, + required: ["city"], + }, + timeoutMs: 5000, + examples: [{ description: "Weather in Tokyo", input: { city: "Tokyo" } }], + commandAliases: ["weather"], + handler: async ({ city }: { city: string }) => { + // Real host access lives here, behind the tool boundary. The guest + // never gets the network credential, only the curated result. + const res = await fetch(`https://example.com/weather?city=${city}`); + return await res.json(); + }, + }, + }, +}); +``` + +The full type shape is in the [TypeScript SDK reference](/docs/sdks/typescript). + +## Invoking a tool from the guest + +Guest code calls a tool with the `callHostTool(name, input)` global. It returns a promise that resolves with the host handler's JSON result: + +```ts +await rt.exec(` + const { temp_f } = await callHostTool("get-weather", { city: "Tokyo" }); + console.log(temp_f); // 75 +`); +``` + +`callHostTool` is available in every guest program run through `exec`, `run`, and `spawn`. A `commandAlias` (for example `weather` above) works in place of the registered key. + +Under the hood, a registered tool is exposed two ways: + +- **As a `PATH` command**: resolved as `/usr/bin/` inside the VM, so the same invocation can be driven directly through `node:child_process` if you prefer. +- **Via `callHostTool`**: a thin wrapper over exactly that command path, so both share the same permission and validation behavior. + +```ts +await rt.exec(` + import { execFileSync } from "node:child_process"; + + const input = { city: "Tokyo" }; + // argv[0] is the command name, then --json and the JSON-encoded input. + const out = execFileSync("get-weather", ["get-weather", "--json", JSON.stringify(input)]); + // The raw command writes a { ok, result } envelope; the handler's return + // value is under "result". callHostTool unwraps this for you. + const { ok, result } = JSON.parse(out.toString()); + console.log(result.temp_f); // 75 +`); +``` + +## The `tool` permission scope + +Tool invocation is gated by the `tool` permission scope. + +- When you pass `tools` to `create()` and set **no** `tool` policy, the `tool` scope is auto-granted so your tools are invocable out of the box. +- Otherwise grant it explicitly so tools can run: + +```ts +const rt = await NodeRuntime.create({ + tools: { /* ... */ }, + permissions: { tool: "allow" }, +}); +``` + +Use a rule set instead of `"allow"` for per-tool gating, allowing some tool names while denying others. See [Permissions](/docs/features/permissions) for rule-set semantics. + +## Wiring a tool into an LLM agent + +Bindings pair naturally with an LLM agent: expose a sandbox capability to the model as a tool and let the model drive it through its own tool-calling loop. + +The example below uses the Vercel AI SDK to give the model a `runJs` tool whose `execute` runs guest code inside the runtime. The model-generated code is untrusted input, but it executes only inside the VM under the secure-default policy (network denied here), so the model can experiment freely without reaching the host. + +```ts +import { NodeRuntime } from "secure-exec"; +import { generateText, tool } from "ai"; +import { openai } from "@ai-sdk/openai"; +import { z } from "zod"; + +const rt = await NodeRuntime.create({ permissions: { network: "deny" } }); + +await generateText({ + model: openai("gpt-4o"), + prompt: "Compute the 10th Fibonacci number by writing JavaScript.", + tools: { + runJs: tool({ + description: "Run JavaScript inside the sandbox and capture its output.", + inputSchema: z.object({ code: z.string() }), + execute: async ({ code }) => { + const result = await rt.exec(code); + return { stdout: result.stdout, stderr: result.stderr }; + }, + }), + }, +}); +``` \ No newline at end of file diff --git a/website/public/docs/docs/features/child-processes.md b/website/public/docs/docs/features/child-processes.md new file mode 100644 index 000000000..f2d02dfb8 --- /dev/null +++ b/website/public/docs/docs/features/child-processes.md @@ -0,0 +1,97 @@ +# Child Processes + +Spawn child processes from sandboxed code. + +Two ways to run processes in Secure Exec: + +- **Guest `node:child_process`**: guest code spawns commands inside the VM. Every child is a kernel-managed process, never a real host process. +- **`rt.spawn(code)`**: the host starts a long-running guest program and gets a live handle (`pid`, `writeStdin`, `kill`, `wait`, `exitCode`). + +## Guest child_process + +Guest code uses the standard `node:child_process` module to spawn commands available in the VM (`sh`, `node`, and the mounted coreutils): + +Output: + +``` +exitCode: 0 +guest stdout: +sh output: hello from a child process +child node version: v22.0.0 +``` + +- `execFileSync` is used for brevity; the async/streaming APIs (`spawn`, `exec`, `execFile`) also work for incremental stdout/stderr or writing to a child's stdin. +- Children run any command provided by the mounted runtimes. By default that is WASM-backed `sh` + coreutils and V8-backed `node`. +- Point at a different set of WASM command binaries with `commandsDir`: + +```ts +const rt = await NodeRuntime.create({ + commandsDir: "/path/to/wasm/commands", +}); +``` + +Child processes always run inside the kernel. Guest code cannot reach a real host process or host binary; `node:child_process` only sees the commands the VM mounts. + +### Where the commands come from + +The guest `sh` and the coreutils it drives ship as WASM binaries. The kernel cannot spawn any guest process without them, so they are mounted through the WASM runtime at boot. This is how `node:child_process` and the shell work inside the VM with no host processes ever involved. + +The `commandsDir` create option overrides where those WASM command binaries are loaded from. When unset, the runtime resolves a directory using the first match in this order: + +1. an explicit `commandsDir` option, +2. the `SECURE_EXEC_WASM_COMMANDS_DIR` environment variable, +3. the in-repo build output (`registry/native/target/wasm32-wasip1/release/commands`), present only in developer checkouts, +4. the commands vendored into the installed `@secure-exec/core` package (published installs). + +The in-repo build output wins over the bundled copy so local edits are picked up without re-vendoring; a fresh `npm install` has no in-repo path and falls through to the vendored commands. See the [TypeScript SDK reference](/docs/sdks/typescript) for the full create-option shape. + +## Long-running guests with rt.spawn + +`rt.exec` runs to completion and returns captured output. `rt.spawn(code)` returns a live handle immediately while the guest keeps running. It is the building block for dev servers and other long-lived guests. + +```ts +const proc = await rt.spawn(` + process.stdin.on("data", (chunk) => { + process.stdout.write("got: " + chunk.toString()); + }); +`); + +proc.writeStdin("hello\n"); // feed stdin +proc.closeStdin(); // signal end-of-input + +const exitCode = await proc.wait(); +console.log(proc.pid, exitCode); +``` + +See the [TypeScript SDK reference](/docs/sdks/typescript) for the full `NodeRuntimeProcess` and `NodeRuntimeSpawnOptions` shapes. Stream output by passing `onStdout` / `onStderr`, which receive raw `Uint8Array` chunks: + +```ts +const proc = await rt.spawn("setInterval(() => console.log('tick'), 100)", { + onStdout: (chunk) => process.stdout.write(new TextDecoder().decode(chunk)), +}); +// ... later +proc.kill(); // SIGTERM +await proc.wait(); +``` + +### Driving a guest server + +Spawn a server, wait for it to listen, then drive requests into it with `rt.fetch`, entirely inside the VM, even when guest network egress is denied: + +```ts +const server = await rt.spawn(` + import http from "node:http"; + http.createServer((_, res) => res.end("ok")).listen(3000); +`); + +const listener = await rt.waitForListener({ port: 3000 }); +const res = await rt.fetch(listener.port ?? 3000, { path: "/" }); +console.log(res.status, res.body); // 200 ok + +server.kill(); +await server.wait(); +``` + +## Underlying process model + +- The kernel process table, signals, and shell that back `node:child_process` and `rt.spawn` are documented in agentOS: [Processes & Shell](https://agentos-sdk.dev/docs/processes). \ No newline at end of file diff --git a/website/public/docs/docs/features/executing-code.md b/website/public/docs/docs/features/executing-code.md new file mode 100644 index 000000000..ab5794b6f --- /dev/null +++ b/website/public/docs/docs/features/executing-code.md @@ -0,0 +1,63 @@ +# Executing Code + +Run guest JavaScript with exec() and run(), and return values from the sandbox. + +`exec()` and `run()` are the two ways to run guest code to completion. The code +runs inside the VM as a standard ES module, so top-level `import` and top-level +`await` both work. + +## Run code and capture output + +`exec()` runs the code and resolves with `stdout`, `stderr`, and `exitCode`. + +```ts +import { NodeRuntime } from "secure-exec"; + +const rt = await NodeRuntime.create(); +const { stdout, exitCode } = await rt.exec(` + import os from "node:os"; + console.log("platform:", os.platform()); +`); +console.log(stdout, exitCode); +await rt.dispose(); +``` + +## Return a value from the guest + +`run()` does everything `exec()` does and also decodes a JSON-serializable +value the guest hands back with the injected `globalThis.__return(value)`. If the +guest never calls it, `value` is `undefined`. + +```ts +const { value } = await rt.run<{ sum: number }>(` + globalThis.__return({ sum: 2 + 40 }); +`); +console.log(value?.sum); // 42 +``` + +## Per-run options + +`exec()` and `run()` take the same per-call options: `stdin` to pipe input, `env` +and `cwd` to override the environment for one run, a `timeout` and an +`AbortSignal` to bound it, and `onStdout` / `onStderr` to stream output as it is +produced. + +```ts +const result = await rt.run( + ` + let input = ""; + for await (const chunk of process.stdin) input += chunk; + globalThis.__return(input.trim().toUpperCase()); + `, + { stdin: "piped through stdin", timeout: 10_000 }, +); +``` + +Guest code can also invoke host-side tools you register with the `tools` option +on `NodeRuntime.create()`: each becomes a named command the guest runs by name, +round-tripping its JSON input to a handler on the host. For the full option and +result shapes, see the [TypeScript SDK reference](/docs/sdks/typescript). + +*[See Full Example](https://github.com/rivet-dev/secure-exec/tree/main/examples/docs/sdk-overview)* + +## Related \ No newline at end of file diff --git a/website/public/docs/docs/features/filesystem.md b/website/public/docs/docs/features/filesystem.md new file mode 100644 index 000000000..603541e68 --- /dev/null +++ b/website/public/docs/docs/features/filesystem.md @@ -0,0 +1,15 @@ +# Filesystem + +A short overview of the Secure Exec filesystem, with a link to the canonical agentOS filesystem docs. + +Each VM presents a normal POSIX filesystem to guest code, backed by a virtual filesystem inside the kernel. At a glance: + +- **Per-VM virtual filesystem**: Every VM gets its own isolated virtual filesystem. One VM cannot see or reach another VM's files. +- **Never touches the host disk**: Guest filesystem calls are served entirely inside the kernel and never read or write the real host disk. +- **Normal POSIX and Node APIs**: The standard `node:fs` and `node:fs/promises` APIs work as usual against the virtual filesystem, so ordinary programs run unchanged. +- **Mountable backends**: You can project host-backed sources into the guest filesystem, Docker-style, including host directories and S3. Mounts are confined to their root, and the guest sees only the mounted subtree. +- **`nodeModules` is a mount**: `NodeRuntime.create({ nodeModules })` is a convenience for a read-only host-directory mount. It projects a host `node_modules` tree at guest `/tmp/node_modules` using the same mount machinery as `mounts`, placed on the package-resolution path. See [Module loading](/docs/features/module-loading). + +## Full reference + +The canonical filesystem API, including seeding files, host-boundary file exchange, and the full mount and backend configuration, is owned by agentOS. \ No newline at end of file diff --git a/website/public/docs/docs/features/module-loading.md b/website/public/docs/docs/features/module-loading.md new file mode 100644 index 000000000..6dc5d8c02 --- /dev/null +++ b/website/public/docs/docs/features/module-loading.md @@ -0,0 +1,67 @@ +# NPM & Module Loading + +How sandboxed code resolves and loads modules. + +Guest `import` and `require` resolve against the VM's virtual filesystem, never the host module loader. Resolution runs entirely inside the kernel. By default the guest sees an empty `node_modules`; project host packages into the VM with `nodeModules` (or `mounts`) to run real npm packages (including the TypeScript compiler) in-sandbox. + +## Loading Modules + +- Guest source runs as a standard ES module: `import`, `import.meta.url`, and top-level `await` all work. +- Build a CommonJS `require` with `createRequire(import.meta.url)`. +- Both paths resolve through the kernel's module loader. + +``` +exitCode: 0 +guest stdout: +resolved node:path via import -> /workspace/data/report.txt +resolved node:os via require -> linux +{"basename":"report.txt","joined":"/workspace/data/report.txt","platform":"linux"} +``` + +Resolution runs inside the kernel against the guest's virtual filesystem. The guest only sees what is present there; mounting host `node_modules` (below) makes those packages part of that filesystem so they resolve like any other guest module. + +## Loading real npm packages + +Put package bytes on the guest filesystem, then let the in-kernel resolver walk them. Three ways to project them: + +- `create({ nodeModules })`: a convenience for a read-only host-directory mount that projects a whole host `node_modules` tree in one call. It uses the same mount machinery as `mounts`, defaulting to guest `/tmp/node_modules`, which is where the resolution walk begins for a program run by `exec()` / `run()` (each program is written under `/tmp`). Pass the object form (`{ hostPath, guestPath }`) to mount it elsewhere. +- `create({ mounts })`: project one host directory at a time onto a guest path, Docker-style. Use a `mounts` entry per package when you want fine-grained control instead of the whole tree. +- `create({ files })` or `rt.writeFile`: write bytes directly into the VM when you want to seed files instead of projecting a host tree. + +Either way the host filesystem is never exposed; the guest sees only the projected subtree or the bytes you write. For the full mount shapes see [the TypeScript SDK reference](/docs/sdks/typescript). + +The example below points `nodeModules` at the host directory that holds `is-number`, then imports it from inside the VM. The guest resolves it the way Node would over a real filesystem, including through `createRequire`. + +``` +exitCode: 0 +guest stdout: +loaded real npm package is-number +{"isNumber(42)":true,"isNumber(\"3.14\")":true,"isNumber(\"nope\")":false,"sameModule":true} +``` + +## node_modules resolution + +When a guest filesystem contains `node_modules`, the resolver matches naive Node.js resolution over it, Docker-style: + +- ancestor `node_modules` walk from the importing module up to the root, +- `package.json` `exports`/`imports` and conditions, +- `realpath`/symlink following. + +No package-manager-specific heuristics: pnpm/yarn layouts resolve because the VFS exposes their symlinks, not because the resolver special-cases them. + +A `nodeModules` (or `mounts`) host mount confines reads to the mounted directory: symlinks are followed only while they stay **inside** the mount root. A single-project `npm`/`pnpm` install resolves fine because its symlinks (including the `.pnpm` store) live inside `node_modules`. A workspace/monorepo install is different: pnpm/yarn and `file:` deps symlink packages to the workspace root or an external store, **outside** the leaf `node_modules`. Those targets are not followed, and the guest import fails with `Cannot resolve module '': not found`. Fix it by pointing the mount at a directory that contains every symlink target (for example the workspace root, mounted at the guest path the program resolves from) instead of the leaf `node_modules`. + +## Seeding files directly + +When you don't have a host directory to mount, write bytes into the VM: + +```ts +// At boot. +const rt = await NodeRuntime.create({ + files: { "/tmp/node_modules/greet/index.js": "module.exports = () => 'hi';" }, +}); + +// Or after boot. +await rt.writeFile("/tmp/node_modules/greet/package.json", '{"main":"index.js"}'); +const bytes = await rt.readFile("/tmp/node_modules/greet/index.js"); +``` \ No newline at end of file diff --git a/website/public/docs/docs/features/networking.md b/website/public/docs/docs/features/networking.md new file mode 100644 index 000000000..dd4c4d91f --- /dev/null +++ b/website/public/docs/docs/features/networking.md @@ -0,0 +1,14 @@ +# Networking + +A short overview of Secure Exec networking, with a link to the canonical agentOS networking docs. + +Secure Exec virtualizes all VM networking so guest code never touches the real host network. At a glance: + +- **One kernel socket table**: Guest `fetch()`, `node:http`, and raw sockets all flow through the kernel socket table, never the real host network. +- **Loopback-only by default**: A guest can bind and reach loopback services inside its own VM, but the socket table stays hermetic and cannot reach a real host loopback service. +- **Allowlist-gated egress**: Outbound networking is denied by default and opted into via the `network` permission, either allowing everything or scoping to specific patterns. +- **Proxied host-to-guest**: Host loopback ports are not visible to the guest unless explicitly exposed through `loopbackExemptPorts`. + +## Full reference + +The canonical networking API, permission rules, and egress details are owned by agentOS. \ No newline at end of file diff --git a/website/public/docs/docs/features/output-capture.md b/website/public/docs/docs/features/output-capture.md new file mode 100644 index 000000000..625350cff --- /dev/null +++ b/website/public/docs/docs/features/output-capture.md @@ -0,0 +1,92 @@ +# Output Capture + +Capture console output from sandboxed code. + +`exec()` runs guest code and resolves with its captured output once the guest process exits. + +- `stdout` and `stderr` are buffered as separate strings, so output on one channel never bleeds into the other. +- `exitCode` is the guest process's exit status. +- Buffering into strings bounds host memory: each channel is held as one string, not an unbounded backlog of live chunks. + +## Capturing output + +Prints: + +``` +exitCode: 3 +stdout: "hello from the sandbox\n" +stderr: "oops from the sandbox\n" +``` + +`process.exit(3)` is why `exitCode` is `3`. + +`run()` adds one more field. It resolves to the same `stdout`, `stderr`, and `exitCode`, plus a decoded `value` the guest hands back by calling `globalThis.__return(value)`: + +```ts +const { value, exitCode } = await rt.run(` + const sum = [1, 2, 3].reduce((a, b) => a + b, 0); + globalThis.__return({ sum }); +`); + +console.log(exitCode, value); // 0 { sum: 6 } +``` + +`value` is the JSON-decoded argument passed to `__return()`. It is only populated when `exitCode === 0` and the guest actually called `__return()`; otherwise it is `undefined`, while `stdout`, `stderr`, and `exitCode` are still captured. + +See [the TypeScript SDK reference](/docs/sdks/typescript) for the full result and option shapes. + +## Streaming output + +Pass `onStdout` / `onStderr` to observe output incrementally as it is produced. The full strings are still returned when the run ends. + +- Each callback receives a `Uint8Array` chunk. Decode text with a `TextDecoder`. +- Available on both `exec()` and `run()`, and on `spawn()` via `NodeRuntimeSpawnOptions`. + +```ts +const decoder = new TextDecoder(); + +const { stdout, exitCode } = await rt.exec( + ` + for (let i = 0; i < 3; i++) console.log("tick", i); + `, + { + onStdout: (chunk) => process.stdout.write(decoder.decode(chunk)), + onStderr: (chunk) => process.stderr.write(decoder.decode(chunk)), + }, +); +// stdout still holds the complete buffered output after the run. +``` + +## Feeding input and cancelling + +`exec()`, `run()`, and `spawn()` take the same options object. Beyond the streaming hooks above, the common ones are `stdin` to pipe input in, `signal` to cancel, plus `env`, `cwd`, and `timeout`. The [TypeScript SDK reference](/docs/sdks/typescript) lists them all. + +Feed input and read everything back as buffered strings: + +```ts +const { stdout } = await rt.exec( + `process.stdin.pipe(process.stdout);`, + { stdin: "echo me back\n" }, +); +// stdout === "echo me back\n" +``` + +Cancel an in-flight run with `signal`; the guest process is killed inside the VM and the call rejects with the abort reason: + +```ts +const controller = new AbortController(); +const pending = rt.exec("while (true) {}", { signal: controller.signal }); +controller.abort(); +await pending.catch((err) => console.log(err.name)); // "AbortError" +``` + +## Common patterns + +Use `exitCode` to detect failure, with `stderr` for the diagnostic: + +```ts +const { stderr, exitCode } = await rt.exec(code); +if (exitCode !== 0) throw new Error(`guest exited ${exitCode}: ${stderr}`); +``` + +For long-running guests that never exit (dev servers), use `spawn()` instead: it returns a live `NodeRuntimeProcess` handle with the same `onStdout`/`onStderr` streaming, plus `writeStdin`, `kill`, and `wait()`. \ No newline at end of file diff --git a/website/public/docs/docs/features/permissions.md b/website/public/docs/docs/features/permissions.md new file mode 100644 index 000000000..d777201bc --- /dev/null +++ b/website/public/docs/docs/features/permissions.md @@ -0,0 +1,15 @@ +# Permissions + +A short overview of Secure Exec permissions, with a link to the canonical agentOS permissions docs. + +Secure Exec checks a per-domain permission policy against every guest syscall, so denied operations are rejected before any host resource is touched. At a glance: + +- **Per-domain policy**: Each domain (`fs`, `network`, `childProcess`, `process`, `env`, `tool`) is configured independently against every guest syscall. +- **Allow, deny, or rules**: A domain takes a mode (`"allow"` or `"deny"`) or a rule set (`{ default, rules }`) for fine-grained control. +- **Enforced before the host**: A denied operation is rejected with `EACCES` before any host resource (socket, file) is opened. +- **Secure defaults**: The network is deny-by-default; filesystem, child processes, process info, and env are enabled so normal programs run. +- **Trusted policy, untrusted subject**: The policy is set by the host, but the guest is the subject it binds. A denied domain holds even when guest code actively tries to escape it. + +## Full reference + +The complete permission scopes, modes, and rule configuration are owned by agentOS. \ No newline at end of file diff --git a/website/public/docs/docs/features/resident-runner.md b/website/public/docs/docs/features/resident-runner.md new file mode 100644 index 000000000..c73d89958 --- /dev/null +++ b/website/public/docs/docs/features/resident-runner.md @@ -0,0 +1,45 @@ +# Resident Runner + +Reuse a live guest process for low-latency repeated execution. + +Each `exec()` / `run()` call starts a fresh guest process, which is the right +default for isolation between runs. When you run many small snippets against the +same runtime (an evaluation loop, a REPL, a test harness), that per-run process +startup dominates. A resident runner keeps one guest process alive and evaluates +each snippet in it, so repeated calls are fast. + +A resident runner trades per-run process isolation for speed: snippets share the +same process, so in-memory state can carry between calls. Use it for trusted, +repeated evaluation. For isolation between runs, use `exec()` / `run()`. + +## Creating and using a runner + +`createResidentRunner()` returns a handle with `exec()` and `dispose()`. Dispose +it when you are done so the live process is torn down. + +```ts +import { NodeRuntime } from "secure-exec"; + +const rt = await NodeRuntime.create(); +const runner = await rt.createResidentRunner(); +try { + const a = await runner.exec("console.log(1 + 1)"); + const b = await runner.exec("console.log(2 + 2)"); + console.log(a.stdout.trim(), b.stdout.trim()); // "2" "4" +} finally { + await runner.dispose(); + await rt.dispose(); +} +``` + +Each `runner.exec(code, options?)` resolves with the same +`{ stdout, stderr, exitCode }` shape as `rt.exec()`. Pass `options.timeout` to +bound a single evaluation. + +## When to use it + +A warm resident evaluation runs in roughly a millisecond, versus the hundreds of +milliseconds a cold run pays to stand up a guest process. Reach for a resident +runner when the same runtime runs many small snippets and the snippets are +trusted to share a process. See the measured difference in +[Benchmarks](/docs/benchmarks). \ No newline at end of file diff --git a/website/public/docs/docs/features/resource-limits.md b/website/public/docs/docs/features/resource-limits.md new file mode 100644 index 000000000..dbd9d1c52 --- /dev/null +++ b/website/public/docs/docs/features/resource-limits.md @@ -0,0 +1,255 @@ +# Resource Limits + +Secure Exec resource limits, defaults, backpressure constants, and warning names. + +Secure Exec bounds each VM with per-VM resource caps so untrusted guest code can never exhaust the host. At a glance: + +- **Per-VM caps**: Each VM gets its own ceilings on concurrent processes, open file descriptors, sockets, total filesystem bytes, and WASM stack depth. +- **Kernel-enforced**: The kernel mediates and accounts for every allocation. There is no path for the guest to reach host resources around these limits. +- **Guest-local failure**: A guest that exceeds a cap fails inside its own VM with a normal POSIX errno, exactly as it would on real Linux. +- **Host is unaffected**: Hitting a limit terminates or fails the guest operation only; the sidecar and host process stay intact and the VM keeps running. +- **Operator-raisable**: The caller configures the limits per VM and can raise or lower them to fit the workload. +- **Observable**: Queue, resource, memory, and CPU limits emit `limit_warning` structured events and `WARN` logs as they approach or hit a cap. + +## Operator constants + +These constants are the default caps behind the `limits.*` VM config fields. + +| Config field | Constant | Default | +| --- | --- | --- | +| `limits.resources.cpuCount` | `DEFAULT_VIRTUAL_CPU_COUNT` | `1` | +| `limits.resources.maxProcesses` | `DEFAULT_MAX_PROCESSES` | `256` | +| `limits.resources.maxOpenFds` | `DEFAULT_MAX_OPEN_FDS` | `256` | +| `limits.resources.maxPipes` | `DEFAULT_MAX_PIPES` | `128` | +| `limits.resources.maxPtys` | `DEFAULT_MAX_PTYS` | `128` | +| `limits.resources.maxSockets` | `DEFAULT_MAX_SOCKETS` | `256` | +| `limits.resources.maxConnections` | `DEFAULT_MAX_CONNECTIONS` | `256` | +| `limits.resources.maxSocketBufferedBytes` | `DEFAULT_MAX_SOCKET_BUFFERED_BYTES` | `4 MiB` | +| `limits.resources.maxSocketDatagramQueueLen` | `DEFAULT_MAX_SOCKET_DATAGRAM_QUEUE_LEN` | `1024` | +| `limits.resources.maxFilesystemBytes` | `DEFAULT_MAX_FILESYSTEM_BYTES` | `64 MiB` | +| `limits.resources.maxInodeCount` | `DEFAULT_MAX_INODE_COUNT` | `16384` | +| `limits.resources.maxBlockingReadMs` | `DEFAULT_BLOCKING_READ_TIMEOUT_MS` | `5000 ms` | +| `limits.resources.maxPreadBytes` | `DEFAULT_MAX_PREAD_BYTES` | `64 MiB` | +| `limits.resources.maxFdWriteBytes` | `DEFAULT_MAX_FD_WRITE_BYTES` | `64 MiB` | +| `limits.resources.maxProcessArgvBytes` | `DEFAULT_MAX_PROCESS_ARGV_BYTES` | `1 MiB` | +| `limits.resources.maxProcessEnvBytes` | `DEFAULT_MAX_PROCESS_ENV_BYTES` | `1 MiB` | +| `limits.resources.maxReaddirEntries` | `DEFAULT_MAX_READDIR_ENTRIES` | `4096` | +| `limits.resources.maxWasmMemoryBytes` | `DEFAULT_MAX_WASM_MEMORY_BYTES` | `128 MiB` | +| `limits.resources.maxWasmFuel` | none | unset, runtime default applies | +| `limits.resources.maxWasmStackBytes` | none | unset, engine default applies | +| `limits.http.maxFetchResponseBytes` | `DEFAULT_MAX_FETCH_RESPONSE_BYTES` | `1 MiB` | +| `limits.tools.defaultToolTimeoutMs` | `DEFAULT_TOOL_TIMEOUT_MS` | `30000 ms` | +| `limits.tools.maxToolTimeoutMs` | `MAX_TOOL_TIMEOUT_MS` | `300000 ms` | +| `limits.tools.maxRegisteredToolkits` | `MAX_REGISTERED_TOOLKITS` | `64` | +| `limits.tools.maxRegisteredToolsPerVm` | `MAX_REGISTERED_TOOLS_PER_VM` | `256` | +| `limits.tools.maxToolsPerToolkit` | `MAX_TOOLS_PER_TOOLKIT` | `64` | +| `limits.tools.maxToolSchemaBytes` | `MAX_TOOL_SCHEMA_BYTES` | `16 KiB` | +| `limits.tools.maxToolExamplesPerTool` | `MAX_TOOL_EXAMPLES_PER_TOOL` | `16` | +| `limits.tools.maxToolExampleInputBytes` | `MAX_TOOL_EXAMPLE_INPUT_BYTES` | `4 KiB` | +| `limits.plugins.maxPersistedManifestBytes` | `MAX_PERSISTED_MANIFEST_BYTES` | `64 MiB` | +| `limits.plugins.maxPersistedManifestFileBytes` | `MAX_PERSISTED_MANIFEST_FILE_BYTES` | `1 GiB` | +| `limits.acp.maxReadLineBytes` | `DEFAULT_ACP_MAX_READ_LINE_BYTES` | `16 MiB` | +| `limits.acp.stdoutBufferByteLimit` | `DEFAULT_ACP_STDOUT_BUFFER_BYTE_LIMIT` | `1 MiB` | +| `limits.jsRuntime.v8HeapLimitMb` | `DEFAULT_V8_HEAP_LIMIT_MB` | `128 MiB` | +| `limits.jsRuntime.capturedOutputLimitBytes` | `DEFAULT_JS_CAPTURED_OUTPUT_LIMIT_BYTES` | `16 MiB` | +| `limits.jsRuntime.stdinBufferLimitBytes` | `DEFAULT_JS_STDIN_BUFFER_LIMIT_BYTES` | `16 MiB` | +| `limits.jsRuntime.eventPayloadLimitBytes` | `DEFAULT_JS_EVENT_PAYLOAD_LIMIT_BYTES` | `1 MiB` | +| `limits.jsRuntime.v8IpcMaxFrameBytes` | `DEFAULT_V8_IPC_MAX_FRAME_BYTES` | `64 MiB` | +| `limits.jsRuntime.syncRpcWaitTimeoutMs` | none | unset, engine default applies | +| `limits.python.outputBufferMaxBytes` | `DEFAULT_PYTHON_OUTPUT_BUFFER_MAX_BYTES` | `1 MiB` | +| `limits.python.executionTimeoutMs` | `DEFAULT_PYTHON_EXECUTION_TIMEOUT_MS` | `300000 ms` | +| `limits.python.maxOldSpaceMb` | `DEFAULT_PYTHON_MAX_OLD_SPACE_MB` | `0`, Pyodide engine default | +| `limits.python.vfsRpcTimeoutMs` | `DEFAULT_PYTHON_VFS_RPC_TIMEOUT_MS` | `30000 ms` | +| `limits.wasm.maxModuleFileBytes` | `DEFAULT_WASM_MAX_MODULE_FILE_BYTES` | `256 MiB` | +| `limits.wasm.capturedOutputLimitBytes` | `DEFAULT_WASM_CAPTURED_OUTPUT_LIMIT_BYTES` | `16 MiB` | +| `limits.wasm.syncReadLimitBytes` | `DEFAULT_WASM_SYNC_READ_LIMIT_BYTES` | `16 MiB` | + +## Backpressure constants + +These internal queue caps are not per-VM config fields. They are tracked so slow consumers produce `limit_warning` events instead of silent stalls. + +| Warning name | Constant | Default | +| --- | --- | --- | +| `javascript_event_channel` | `JAVASCRIPT_EVENT_CHANNEL_CAPACITY` | `512 frames` | +| `v8_session_frames` | `V8_SESSION_FRAME_CHANNEL_CAPACITY` | `1024 frames` | +| `sidecar_stdin_frames` | `MAX_STDIN_FRAME_QUEUE` | `128 frames` | +| `sidecar_stdout_frames` | `MAX_STDOUT_FRAME_QUEUE` | `4096 frames` | +| `completed_sidecar_responses` | `MAX_COMPLETED_SIDECAR_RESPONSES` | `10000 responses` | + +## Audited constants + +The limits audit classifies every limit-shaped constant as `policy`, `policy-deferred`, or `invariant`. Keep this table in sync with `crates/sidecar/tests/fixtures/limits-inventory.json`. + +| Constant | Class | Source | +| --- | --- | --- | +| `MAX_SYMLINK_DEPTH` | `invariant` | `crates/execution/assets/v8-bridge.source.js` | +| `MAX_BENCHMARK_ITERATIONS` | `invariant` | `crates/execution/src/benchmark.rs` | +| `MAX_BENCHMARK_WARMUP_ITERATIONS` | `invariant` | `crates/execution/src/benchmark.rs` | +| `JAVASCRIPT_CAPTURED_OUTPUT_LIMIT_BYTES` | `policy` | `crates/execution/src/javascript.rs` | +| `JAVASCRIPT_EVENT_CHANNEL_CAPACITY` | `invariant` | `crates/execution/src/javascript.rs` | +| `JAVASCRIPT_EVENT_PAYLOAD_LIMIT_BYTES` | `policy` | `crates/execution/src/javascript.rs` | +| `KERNEL_STDIN_BUFFER_LIMIT_BYTES` | `policy` | `crates/execution/src/javascript.rs` | +| `NODE_SYNC_RPC_RESPONSE_QUEUE_CAPACITY` | `invariant` | `crates/execution/src/javascript.rs` | +| `DEFAULT_NODE_IMPORT_CACHE_MATERIALIZE_TIMEOUT` | `invariant` | `crates/execution/src/node_import_cache.rs` | +| `DEFAULT_PYTHON_EXECUTION_TIMEOUT_MS` | `policy` | `crates/execution/src/python.rs` | +| `DEFAULT_PYTHON_MAX_OLD_SPACE_MB` | `policy` | `crates/execution/src/python.rs` | +| `DEFAULT_PYTHON_OUTPUT_BUFFER_MAX_BYTES` | `policy` | `crates/execution/src/python.rs` | +| `DEFAULT_PYTHON_VFS_RPC_TIMEOUT_MS` | `policy` | `crates/execution/src/python.rs` | +| `V8_SESSION_FRAME_CHANNEL_CAPACITY` | `invariant` | `crates/execution/src/v8_host.rs` | +| `MAX_FRAME_SIZE` | `policy` | `crates/execution/src/v8_ipc.rs` | +| `DEFAULT_WASM_EXECUTION_TIMEOUT_MS` | `policy-deferred` | `crates/execution/src/wasm.rs` | +| `DEFAULT_WASM_PREWARM_TIMEOUT_MS` | `invariant` | `crates/execution/src/wasm.rs` | +| `MAX_SYNC_WASM_PREWARM_MODULE_BYTES` | `invariant` | `crates/execution/src/wasm.rs` | +| `MAX_WASM_IMPORT_SECTION_ENTRIES` | `invariant` | `crates/execution/src/wasm.rs` | +| `MAX_WASM_MEMORY_SECTION_ENTRIES` | `invariant` | `crates/execution/src/wasm.rs` | +| `MAX_WASM_MODULE_FILE_BYTES` | `policy` | `crates/execution/src/wasm.rs` | +| `MAX_WASM_VARUINT_BYTES` | `invariant` | `crates/execution/src/wasm.rs` | +| `WASM_CAPTURED_OUTPUT_LIMIT_BYTES` | `policy` | `crates/execution/src/wasm.rs` | +| `WASM_SYNC_READ_LIMIT_BYTES` | `policy` | `crates/execution/src/wasm.rs` | +| `DEFAULT_STREAM_DEVICE_READ_BYTES` | `invariant` | `crates/kernel/src/device_layer.rs` | +| `MAX_FDS_PER_PROCESS` | `invariant` | `crates/kernel/src/fd_table.rs` | +| `SHEBANG_LINE_MAX_BYTES` | `invariant` | `crates/kernel/src/kernel.rs` | +| `MAX_SNAPSHOT_DEPTH` | `invariant` | `crates/vfs/src/posix/overlay_fs.rs` | +| `MAX_PIPE_BUFFER_BYTES` | `invariant` | `crates/kernel/src/pipe_manager.rs` | +| `MAX_ALLOCATED_PID` | `invariant` | `crates/kernel/src/process_table.rs` | +| `MAX_SIGNAL` | `invariant` | `crates/kernel/src/process_table.rs` | +| `MAX_CANON` | `invariant` | `crates/kernel/src/pty.rs` | +| `MAX_PTY_BUFFER_BYTES` | `invariant` | `crates/kernel/src/pty.rs` | +| `DEFAULT_BLOCKING_READ_TIMEOUT_MS` | `policy` | `crates/kernel/src/resource_accounting.rs` | +| `DEFAULT_MAX_CONNECTIONS` | `policy` | `crates/kernel/src/resource_accounting.rs` | +| `DEFAULT_MAX_FD_WRITE_BYTES` | `policy` | `crates/kernel/src/resource_accounting.rs` | +| `DEFAULT_MAX_FILESYSTEM_BYTES` | `policy` | `crates/vfs/src/posix/usage.rs` | +| `DEFAULT_MAX_INODE_COUNT` | `policy` | `crates/vfs/src/posix/usage.rs` | +| `DEFAULT_MAX_OPEN_FDS` | `policy` | `crates/kernel/src/resource_accounting.rs` | +| `DEFAULT_MAX_PIPES` | `policy` | `crates/kernel/src/resource_accounting.rs` | +| `DEFAULT_MAX_PREAD_BYTES` | `policy` | `crates/kernel/src/resource_accounting.rs` | +| `DEFAULT_MAX_PROCESS_ARGV_BYTES` | `policy` | `crates/kernel/src/resource_accounting.rs` | +| `DEFAULT_MAX_PROCESS_ENV_BYTES` | `policy` | `crates/kernel/src/resource_accounting.rs` | +| `DEFAULT_MAX_PROCESSES` | `policy` | `crates/kernel/src/resource_accounting.rs` | +| `DEFAULT_MAX_PTYS` | `policy` | `crates/kernel/src/resource_accounting.rs` | +| `DEFAULT_MAX_READDIR_ENTRIES` | `policy` | `crates/kernel/src/resource_accounting.rs` | +| `DEFAULT_MAX_WASM_MEMORY_BYTES` | `policy` | `crates/kernel/src/resource_accounting.rs` | +| `DEFAULT_MAX_SOCKET_BUFFERED_BYTES` | `policy` | `crates/kernel/src/resource_accounting.rs` | +| `DEFAULT_MAX_SOCKET_DATAGRAM_QUEUE_LEN` | `policy` | `crates/kernel/src/resource_accounting.rs` | +| `DEFAULT_MAX_SOCKETS` | `policy` | `crates/kernel/src/resource_accounting.rs` | +| `MAX_PATH_LENGTH` | `invariant` | `crates/vfs/src/posix/vfs.rs` | +| `MAX_SYMLINK_DEPTH` | `invariant` | `crates/vfs/src/posix/vfs.rs` | +| `MAX_PATH` | `invariant` | `crates/vfs/src/engine/types.rs` | +| `MAX_SYMLINK_DEPTH` | `invariant` | `crates/vfs/src/engine/types.rs` | +| `DEFAULT_METADATA_CACHE_ENTRIES` | `invariant` | `crates/sidecar/src/plugins/chunked_local.rs` | +| `DEFAULT_METADATA_CACHE_ENTRIES` | `invariant` | `crates/sidecar/src/plugins/chunked_s3.rs` | +| `CONTROL_FRAME_QUEUE_CAPACITY` | `invariant` | `crates/secure-exec-client/src/transport.rs` | +| `EVENT_CHANNEL_CAPACITY` | `invariant` | `crates/secure-exec-client/src/transport.rs` | +| `PENDING_REQUEST_LIMIT` | `invariant` | `crates/secure-exec-client/src/transport.rs` | +| `REQUEST_FRAME_QUEUE_CAPACITY` | `invariant` | `crates/secure-exec-client/src/transport.rs` | +| `DEFAULT_KERNEL_STDIN_READ_MAX_BYTES` | `invariant` | `crates/sidecar/src/execution.rs` | +| `DEFAULT_KERNEL_STDIN_READ_TIMEOUT_MS` | `invariant` | `crates/sidecar/src/execution.rs` | +| `EXITED_PROCESS_SNAPSHOT_RETENTION` | `invariant` | `crates/sidecar/src/execution.rs` | +| `JAVASCRIPT_NET_POLL_MAX_WAIT` | `invariant` | `crates/sidecar/src/execution.rs` | +| `MAX_JAVASCRIPT_COMMAND_REDIRECT_DEPTH` | `invariant` | `crates/sidecar/src/execution.rs` | +| `MAX_PER_PROCESS_STATE_HANDLES` | `policy-deferred` | `crates/sidecar/src/execution.rs` | +| `SQLITE_JS_SAFE_INTEGER_MAX` | `invariant` | `crates/sidecar/src/execution.rs` | +| `VM_FETCH_BUFFER_LIMIT_BYTES` | `policy` | `crates/sidecar/src/execution.rs` | +| `DEFAULT_ACP_MAX_READ_LINE_BYTES` | `policy` | `crates/sidecar/src/limits.rs` | +| `DEFAULT_ACP_STDOUT_BUFFER_BYTE_LIMIT` | `policy` | `crates/sidecar/src/limits.rs` | +| `DEFAULT_JS_CAPTURED_OUTPUT_LIMIT_BYTES` | `policy` | `crates/sidecar/src/limits.rs` | +| `DEFAULT_JS_EVENT_PAYLOAD_LIMIT_BYTES` | `policy` | `crates/sidecar/src/limits.rs` | +| `DEFAULT_JS_STDIN_BUFFER_LIMIT_BYTES` | `policy` | `crates/sidecar/src/limits.rs` | +| `DEFAULT_MAX_FETCH_RESPONSE_BYTES` | `policy` | `crates/sidecar/src/limits.rs` | +| `DEFAULT_PYTHON_EXECUTION_TIMEOUT_MS` | `policy` | `crates/sidecar/src/limits.rs` | +| `DEFAULT_PYTHON_MAX_OLD_SPACE_MB` | `policy` | `crates/sidecar/src/limits.rs` | +| `DEFAULT_PYTHON_OUTPUT_BUFFER_MAX_BYTES` | `policy` | `crates/sidecar/src/limits.rs` | +| `DEFAULT_PYTHON_VFS_RPC_TIMEOUT_MS` | `policy` | `crates/sidecar/src/limits.rs` | +| `DEFAULT_TOOL_TIMEOUT_MS` | `policy` | `crates/sidecar/src/limits.rs` | +| `DEFAULT_V8_IPC_MAX_FRAME_BYTES` | `policy` | `crates/sidecar/src/limits.rs` | +| `DEFAULT_V8_HEAP_LIMIT_MB` | `policy` | `crates/sidecar/src/limits.rs` | +| `DEFAULT_WASM_CAPTURED_OUTPUT_LIMIT_BYTES` | `policy` | `crates/sidecar/src/limits.rs` | +| `DEFAULT_WASM_MAX_MODULE_FILE_BYTES` | `policy` | `crates/sidecar/src/limits.rs` | +| `DEFAULT_WASM_SYNC_READ_LIMIT_BYTES` | `policy` | `crates/sidecar/src/limits.rs` | +| `MAX_PERSISTED_MANIFEST_BYTES` | `policy` | `crates/sidecar/src/limits.rs` | +| `MAX_PERSISTED_MANIFEST_FILE_BYTES` | `policy` | `crates/sidecar/src/limits.rs` | +| `MAX_REGISTERED_TOOLKITS` | `policy` | `crates/sidecar/src/limits.rs` | +| `MAX_REGISTERED_TOOLS_PER_VM` | `policy` | `crates/sidecar/src/limits.rs` | +| `MAX_TOOL_EXAMPLE_INPUT_BYTES` | `policy` | `crates/sidecar/src/limits.rs` | +| `MAX_TOOL_EXAMPLES_PER_TOOL` | `policy` | `crates/sidecar/src/limits.rs` | +| `MAX_TOOL_SCHEMA_BYTES` | `policy` | `crates/sidecar/src/limits.rs` | +| `MAX_TOOL_TIMEOUT_MS` | `policy` | `crates/sidecar/src/limits.rs` | +| `MAX_TOOLS_PER_TOOLKIT` | `policy` | `crates/sidecar/src/limits.rs` | +| `MAX_PERSISTED_MANIFEST_BYTES` | `policy` | `crates/sidecar/src/plugins/google_drive.rs` | +| `MAX_PERSISTED_MANIFEST_FILE_BYTES` | `policy` | `crates/sidecar/src/plugins/google_drive.rs` | +| `MAX_HOST_DIR_READ_BYTES` | `policy` | `crates/sidecar/src/plugins/host_dir.rs` | +| `DEFAULT_MAX_FULL_READ_BYTES` | `policy-deferred` | `crates/sidecar/src/plugins/sandbox_agent.rs` | +| `DEFAULT_PROCESS_TIMEOUT_MS` | `policy-deferred` | `crates/sidecar/src/plugins/sandbox_agent.rs` | +| `DEFAULT_TIMEOUT_MS` | `policy-deferred` | `crates/sidecar/src/plugins/sandbox_agent.rs` | +| `DEFAULT_COMPLETED_RESPONSE_CAP` | `invariant` | `crates/sidecar/src/protocol.rs` | +| `DEFAULT_MAX_FRAME_BYTES` | `policy` | `crates/sidecar/src/protocol.rs` | +| `DEFAULT_MAX_FRAME_BYTES` | `invariant` | `crates/sidecar/src/wire.rs` | +| `MAX_COMPLETED_SIDECAR_RESPONSES` | `invariant` | `crates/sidecar/src/service.rs` | +| `MAX_OUTBOUND_SIDECAR_REQUESTS` | `invariant` | `crates/sidecar/src/service.rs` | +| `MAX_PENDING_SIDECAR_RESPONSES` | `invariant` | `crates/sidecar/src/service.rs` | +| `MAX_PROCESS_EVENT_QUEUE` | `invariant` | `crates/sidecar/src/service.rs` | +| `HOST_REALPATH_MAX_SYMLINK_DEPTH` | `invariant` | `crates/sidecar/src/state.rs` | +| `VM_LISTEN_PORT_MAX_METADATA_KEY` | `invariant` | `crates/sidecar/src/state.rs` | +| `MAX_EVENT_READY_QUEUE` | `invariant` | `crates/sidecar/src/stdio.rs` | +| `MAX_STDIN_FRAME_QUEUE` | `invariant` | `crates/sidecar/src/stdio.rs` | +| `MAX_STDOUT_FRAME_QUEUE` | `invariant` | `crates/sidecar/src/stdio.rs` | +| `DEFAULT_TOOL_TIMEOUT_MS` | `policy` | `crates/sidecar/src/tools.rs` | +| `MAX_REGISTERED_TOOLKITS` | `policy` | `crates/sidecar/src/tools.rs` | +| `MAX_REGISTERED_TOOLS_PER_VM` | `policy` | `crates/sidecar/src/tools.rs` | +| `MAX_TOOL_DESCRIPTION_LENGTH` | `policy-deferred` | `crates/sidecar/src/tools.rs` | +| `MAX_TOOL_EXAMPLE_INPUT_BYTES` | `policy` | `crates/sidecar/src/tools.rs` | +| `MAX_TOOL_EXAMPLES_PER_TOOL` | `policy` | `crates/sidecar/src/tools.rs` | +| `MAX_TOOL_NAME_LENGTH` | `policy-deferred` | `crates/sidecar/src/tools.rs` | +| `MAX_TOOL_SCHEMA_BYTES` | `policy` | `crates/sidecar/src/tools.rs` | +| `MAX_TOOL_SCHEMA_DEPTH` | `invariant` | `crates/sidecar/src/tools.rs` | +| `MAX_TOOL_TIMEOUT_MS` | `policy` | `crates/sidecar/src/tools.rs` | +| `MAX_TOOLKIT_NAME_LENGTH` | `policy-deferred` | `crates/sidecar/src/tools.rs` | +| `MAX_TOOLS_PER_TOOLKIT` | `policy` | `crates/sidecar/src/tools.rs` | +| `MAX_VM_LAYERS` | `policy-deferred` | `crates/sidecar/src/vm.rs` | +| `MAX_CBOR_BRIDGE_CONTAINER_ITEMS` | `invariant` | `crates/v8-runtime/src/bridge.rs` | +| `MAX_CBOR_BRIDGE_DEPTH` | `invariant` | `crates/v8-runtime/src/bridge.rs` | +| `MAX_PENDING_PROMISES` | `invariant` | `crates/v8-runtime/src/bridge.rs` | +| `MAX_VM_CONTEXTS` | `invariant` | `crates/v8-runtime/src/bridge.rs` | +| `SESSION_OUTPUT_CHANNEL_CAPACITY` | `invariant` | `crates/v8-runtime/src/embedded_runtime.rs` | +| `MAX_CJS_NAMED_EXPORTS` | `invariant` | `crates/v8-runtime/src/execution.rs` | +| `MAX_CJS_RUNTIME_EXPORT_NAME_LEN` | `invariant` | `crates/v8-runtime/src/execution.rs` | +| `MAX_MODULE_BATCH_RESOLVE_RESPONSE_BYTES` | `invariant` | `crates/v8-runtime/src/execution.rs` | +| `MAX_MODULE_PREFETCH_BATCH_SIZE` | `invariant` | `crates/v8-runtime/src/execution.rs` | +| `MAX_MODULE_PREFETCH_GRAPH_MODULES` | `invariant` | `crates/v8-runtime/src/execution.rs` | +| `MAX_MODULE_RESOLVE_CACHE_ENTRIES` | `invariant` | `crates/v8-runtime/src/execution.rs` | +| `MAX_MODULE_RESOLVE_MODULES` | `invariant` | `crates/v8-runtime/src/execution.rs` | +| `MAX_FRAME_SIZE` | `policy` | `crates/v8-runtime/src/ipc_binary.rs` | +| `MAX_UNHANDLED_PROMISE_REJECTIONS` | `invariant` | `crates/v8-runtime/src/isolate.rs` | +| `NEAR_HEAP_LIMIT_HEADROOM_BYTES` | `invariant` | `crates/v8-runtime/src/isolate.rs` | +| `MAX_DEFERRED_SESSION_COMMANDS` | `invariant` | `crates/v8-runtime/src/session.rs` | +| `MAX_DEFERRED_SYNC_MESSAGES` | `invariant` | `crates/v8-runtime/src/session.rs` | +| `SESSION_COMMAND_CHANNEL_CAPACITY` | `invariant` | `crates/v8-runtime/src/session.rs` | +| `MAX_SNAPSHOT_BLOB_BYTES` | `invariant` | `crates/v8-runtime/src/snapshot.rs` | +| `MAX_V8_BRIDGE_CODE_BYTES` | `invariant` | `crates/v8-runtime/src/snapshot.rs` | +| `TRAILING_OUTPUT_DRAIN_MAX_MS` | `invariant` | `packages/core/src/kernel-proxy.ts` | +| `DEFAULT_SIDECAR_EVENT_BUFFER_CAPACITY` | `policy-deferred` | `packages/core/src/native-client.ts` | +| `DEFAULT_SIDECAR_FRAME_TIMEOUT_MS` | `policy-deferred` | `packages/core/src/native-client.ts` | +| `MAX_SYMLINK_DEPTH` | `invariant` | `packages/core/src/test-runtime.ts` | + +## Warning names + +The limit registry emits stable names in `limit_warning.detail.limit`. +`limits.resources.maxWasmStackBytes` is audited as a configured constant above, but it does not emit `limit_warning` until runtime stack enforcement has a reliable exhaustion edge. + +When a warning fires depends on whether the limit has a continuously-sampled usage: + +- **Queue**, **Resource**, and **CPU** limits emit an **edge-triggered ~80% approach warning** (re-armed once usage drains back below ~50%), so the operator gets a heads-up *before* the cap is reached. The CPU budgets (`v8_cpu_time_ms`, `v8_wall_clock_ms`, `wasm_fuel_ms`) are sampled by the execution watchdogs; the queue/resource gauges are sampled as items flow through them. +- **Memory** limits (`v8_heap_bytes`, `wasm_memory_bytes`) emit at the **terminal edge** — V8's near-heap-limit callback fires as the isolate is about to exceed its heap cap, and WASM memory is checked at module-instantiation time. There is no separate 80% heap sample because a V8 isolate cannot be safely read from the watchdog thread. + +CPU budgets therefore emit both the ~80% approach warning *and* a terminal exhaustion warning when the watchdog finally terminates execution. + +| Category | Warning names | +| --- | --- | +| Queue | `javascript_event_channel`, `v8_session_frames`, `sidecar_stdin_frames`, `sidecar_stdout_frames`, `completed_sidecar_responses`, `pending_process_events`, `pending_sidecar_responses`, `outbound_sidecar_requests` | +| Resource | `vm_processes`, `vm_open_fds`, `vm_pipes`, `vm_ptys`, `vm_sockets`, `vm_connections`, `vm_socket_buffered_bytes`, `vm_socket_datagram_queue_len`, `vm_filesystem_bytes`, `vm_inodes` | +| Memory | `v8_heap_bytes`, `wasm_memory_bytes` | +| CPU | `v8_cpu_time_ms`, `v8_wall_clock_ms`, `wasm_fuel_ms` | + +## Related agentOS docs + +agentOS layers its own session and adapter limits on top of Secure Exec. \ No newline at end of file diff --git a/website/public/docs/docs/features/runtime-platform.md b/website/public/docs/docs/features/runtime-platform.md new file mode 100644 index 000000000..fbba80770 --- /dev/null +++ b/website/public/docs/docs/features/runtime-platform.md @@ -0,0 +1,199 @@ +# Runtime & Platform + +Customize the host environment guest code sees (the full Node.js surface today), plus the platform ladder (node, browser, neutral, bare) the kernel models. + +`NodeRuntime.create()` shapes the host environment guest code sees before it +boots, and the kernel models that environment as a ladder of platforms (`node`, +`browser`, `neutral`, `bare`). Guest code always runs inside a kernel-backed V8 +isolate with zero host escapes: every syscall (filesystem, network, child +process) goes through the kernel, never the real host. + +This page covers the customization surface: seeding and selecting the host +environment, then the `moduleResolution` and `allowedBuiltins` knobs the wire +config exposes. Start by probing the default `node` surface: + +Output, the guest host environment as seen from inside the isolate: + +```text +{ + platform: 'linux', + hasProcess: true, + hasBuffer: true, + nodeVersion: '22.0.0', + sha256: 'fa7ce60dac0cc1bfe7424a68e47ad3d712345cf936431bb147cd5f5de0371a4a', + joinedPath: '/home/agentos/report.txt' +} +``` + +**Guest `run()` and `exec()` code both run as ES modules.** Both `rt.run()` and +`rt.exec()` write your code into an `.mjs` module, so top-level `import` and +top-level `await` work in either. `run()` injects a `globalThis.__return(value)` +helper you call to hand a JSON-serializable value back to the host (delivered as +`result.value`); the example uses dynamic `await import("node:…")` purely to keep +the snippet a single expression body. + +## Host environment (the `node` surface) + +Available to guest code on the default platform: + +- **Node globals**: `process`, `Buffer`, `require`, `module`, `__dirname`, `__filename`. +- **`node:*` builtins**: `fs`, `path`, `crypto`, `http`, `net`, `os`, `child_process`, `dns`, and the rest of the Node standard library. +- **Node identity**: virtualized `process.versions` (Node `22.0.0`), `process.platform` (`linux`), `execPath`, and `pid`/`ppid`/`uid`/`gid`. +- **Web platform**: `fetch`, `URL`, `TextEncoder`/`TextDecoder`, WebCrypto, `structuredClone`, `Blob`, `AbortController`. +- **Universal primitives**: `console`, timers (`setTimeout`/`setInterval`/…), `queueMicrotask`. +- **Language + Wasm**: the ECMAScript spec globals plus `WebAssembly`. + +Every one of these is kernel-backed. `fetch` and `node:net`/`node:http` route +through the kernel socket table (and are denied by default until you grant +`network`); `node:fs` sees only the VM's virtual filesystem; `node:child_process` +spawns kernel-managed processes. + +### Seeding the host environment + +`NodeRuntime.create()` shapes what the guest sees before and after boot: + +```ts +const rt = await NodeRuntime.create({ + env: { API_BASE: "https://example.test" }, // guest process env + cwd: "/workspace", // default working dir + files: { "/root/data.json": '{"ok":true}' }, // seed VFS bytes + mounts: [ // project host dirs, Docker-style, lazy + { guestPath: "/root/node_modules/typescript", hostPath: "/abs/typescript", readOnly: true }, + ], + permissions: { network: "allow" }, // merged over secure default (network denied) + tools: { // host capabilities the guest calls as commands + add: { + description: "Add two numbers", + inputSchema: { type: "object", properties: { a: { type: "number" }, b: { type: "number" } }, required: ["a", "b"] }, + handler: ({ a, b }: { a: number; b: number }) => ({ sum: a + b }), + }, + }, + loopbackExemptPorts: [3000], // let non-loopback connections reach this port + commandsDir: "/abs/wasm/commands", // override the WASM `sh`/coreutils dir +}); +``` + +- `files` copies bytes into the VFS up front; `mounts` reads host trees lazily through the VFS, so large `node_modules` are not copied as a blob. +- `permissions` merges over a secure default (`fs`/`childProcess`/`process`/`env` allowed, `network` denied), so `{ network: "allow" }` is enough to opt in. +- `tools` auto-grants the `tool` scope when you set no `tool` policy; the guest invokes a tool by name with `--json` input over `node:child_process`. + +After boot, the same surface is reachable on the live runtime: + +```ts +await rt.writeFile("/root/late.json", '{"added":"after boot"}'); +const bytes = await rt.readFile("/root/late.json"); // Uint8Array +await rt.registerTools({ + now: { description: "epoch ms", inputSchema: { type: "object" }, handler: () => Date.now() }, +}); +``` + +### Driving a guest dev server from the host + +Spawn a long-running guest, wait for it to listen, then drive an HTTP request +into it from the host. This works even with egress denied, because the request +flows through the kernel socket table rather than the real host network: + +```ts +const server = await rt.spawn(` + import http from "node:http"; + http.createServer((_, res) => res.end("ok")).listen(3000); +`); +const listener = await rt.waitForListener({ port: 3000 }); +const res = await rt.fetch(listener.port ?? 3000, { path: "/" }); +server.kill(); +await server.wait(); +``` + +For the full set of run methods (`exec`/`run`/`spawn`/`fetch`/`waitForListener`) +and their per-run options (`env`, `cwd`, `stdin`, `timeout`, `signal`, +`onStdout`/`onStderr`), see the TypeScript SDK reference: + +## The platform ladder + +The kernel models the guest host environment as a ladder, using esbuild's +vocabulary (`node` / `browser` / `neutral`) plus `bare` for the language-only +tier esbuild has no name for. `NodeRuntime` always runs the top rung (`node`); +the lower rungs are described here for context and are **not currently selectable +in Secure Exec** (see the note below). + +| Capability | `node` | `browser` | `neutral` | `bare` | +|---|:---:|:---:|:---:|:---:| +| Node globals | ✅ | No | No | No | +| `node:*` builtins | ✅ | No | No | No | +| Node identity | ✅ | No | No | No | +| Web platform | ✅ | ✅ | No | No | +| Universal primitives | ✅ | ✅ | ✅ | No | +| Language + Wasm | ✅ | ✅ | ✅ | ✅ | + +- **`node`** (the default): full Node.js compatibility. Nothing removed. +- **`browser`**: a browser/Deno-like runtime. The Node surface is gone; web-standard globals remain. `crypto` is the WebCrypto object (`crypto.subtle`, `crypto.getRandomValues`), *not* the `node:crypto` module, so `crypto.randomBytes`/`crypto.createHash` are absent. +- **`neutral`**: universal primitives only (`console`, timers, `queueMicrotask`) plus the language. No `fetch`/`URL`/WebCrypto, no Node. +- **`bare`**: language only: the ECMAScript spec globals plus `WebAssembly`. No `console`, no timers, no `fetch`. The caller provides any host functionality the guest needs. + +`WebAssembly` stays available on **every tier**, including `bare`. Compilation +happens inside the isolate and is not a host escape. + +**Platform selection is not configurable in Secure Exec yet.** The kernel's wire +protocol carries a `jsRuntime` config with `platform`, `moduleResolution`, and +`allowedBuiltins` fields. The tiers are real in the kernel, but +`NodeRuntime.create()` does **not** plumb those fields through: it always boots +the VM on the `node` platform with full Node module resolution. There is no +`NodeRuntime.create()` option to select `browser`/`neutral`/`bare`, change module +resolution, or restrict the builtin allow-list today. The sections below document +the intended model for those fields, not a `create()` option you can pass. + +## `moduleResolution`: how imports resolve + +`moduleResolution` is an independent axis of the `jsRuntime` config (any +combination with `platform` is valid). Set it alongside `platform` to lock down +how `import`/`require` specifiers resolve: + +```ts +const config: CreateVmConfig = { + // … + jsRuntime: { + platform: "node", + moduleResolution: "relative", // only relative/absolute paths resolve from the VFS + }, +}; +``` + +With `moduleResolution: "relative"`, `import "./util.js"` resolves from the +virtual filesystem, while a bare `import "lodash"` or a `node:*` builtin import +fails. The default is full Node resolution, which is what `NodeRuntime` boots: + +| `moduleResolution` | `import "pkg"` | `import "./x.js"` | `node:*` | +|---|:---:|:---:|:---:| +| `node` (default) | ✅ | ✅ | ✅ | +| `relative` | No | ✅ | No | +| `none` | No | No | No | + +(`import "pkg"` = bare/`node_modules` specifier; `import "./x.js"` = relative or +absolute path; `node:*` follows the platform / `allowedBuiltins`.) + +- **`node`**: standard Node resolution: the `node_modules` ancestor walk, `exports`/`imports`/conditions, and `realpath`/symlink following. +- **`relative`**: only relative and absolute paths resolve from the VFS; bare package specifiers and `node:*` builtins do not. +- **`none`**: nothing resolves. Any `import` or `require` (including relative) fails. Produces a single self-contained entrypoint module, useful for locked-down evaluation of one script. + +## `allowedBuiltins`: restrict Node builtins (node platform only) + +`allowedBuiltins` narrows which `node:*` builtin modules guest code may import. +Set it on the `jsRuntime` config to allow exactly the builtins a script needs: + +```ts +const config: CreateVmConfig = { + // … + jsRuntime: { + platform: "node", + allowedBuiltins: ["path", "fs"], // only these resolve; everything else is denied + }, +}; +``` + +With `allowedBuiltins: ["path", "fs"]`, `import("node:path")` and +`import("node:fs/promises")` succeed (a root name like `fs` also covers its +subpaths), while `import("node:child_process")` is rejected. Omitting +`allowedBuiltins` keeps the engine default allow-list (what `NodeRuntime` uses); +`[]` denies all builtins. It is only valid under `platform: "node"`; the other +platforms deny all `node:*` builtins regardless, and unknown builtin names are +rejected. \ No newline at end of file diff --git a/website/public/docs/docs/features/typescript.md b/website/public/docs/docs/features/typescript.md new file mode 100644 index 000000000..73602e688 --- /dev/null +++ b/website/public/docs/docs/features/typescript.md @@ -0,0 +1,81 @@ +# TypeScript + +Compiling and type-checking TypeScript inside the sandbox. + +`@secure-exec/typescript` runs the TypeScript compiler **inside the sandbox**. The `typescript` package is projected into the VM's virtual filesystem and every `createProgram`/`emit` call happens in the guest, so untrusted TypeScript never compiles or runs on the host. + +**Why compile in the sandbox:** type-checking attacker-controlled source is a **CPU and memory amplification** vector. A small malicious type (recursive conditional types, deeply nested generics) can make `tsc` spin for seconds or balloon its heap. Because the compiler runs in a disposable VM, the blow-up is contained by the sandbox boundary, and you can bound each run with a `timeout` instead of hanging or OOM-ing the host. + +## Install + +```bash +npm install @secure-exec/typescript secure-exec +``` + +## Compile and type-check a source string + +Prints: + +``` +Compiled TypeScript to JavaScript inside the sandbox. +exitCode: 0 +guest stdout: +hello secure-exec #1 +hello secure-exec #2 +hello secure-exec #3 +type check success: false + error TS2322 (line 1): Type 'string' is not assignable to type 'number'. +OK: TypeScript compiled and type-checked inside the sandbox. +``` + +Each diagnostic is structured (`code`, `category`, `message`, and a `line`/`column` when available), and `success` is `false` whenever any diagnostic is an error, so you can branch on results without parsing compiler text. + +## Compile a tsconfig.json project + +To compile a whole project, seed a `tsconfig.json` and its sources with `files` (keyed by absolute guest path), then call `compileProject`. You can also project host directories into the VM with `mounts` instead of inlining them. + +```ts +import { createTypeScriptTools } from "@secure-exec/typescript"; + +const tools = createTypeScriptTools({ + files: { + "/root/tsconfig.json": JSON.stringify({ + compilerOptions: { strict: true, target: "ES2022", module: "ESNext" }, + include: ["src"], + }), + "/root/src/index.ts": "export const answer: number = 42;\n", + }, +}); + +// Compile every file the tsconfig includes, emitting into the VM filesystem. +const compiled = await tools.compileProject({ cwd: "/root" }); +console.log("project compiled:", compiled.success); +console.log("emitted:", compiled.emittedFiles); + +// Or type-check only, without emitting any output. +const checked = await tools.typecheckProject({ cwd: "/root" }); +console.log("project type-checks:", checked.success); +``` + +`compileProject` emits into the VM's virtual filesystem (`emittedFiles` lists the paths written). To pull that output back to the host, run the compile on a `NodeRuntime` directly and read the files with `rt.readFile`. + +## Bounding untrusted compiles + +`compileSource`/`typecheckSource` manage their own VM, so the compile is already contained. To put a wall-clock bound on running the *emitted* output (or your own compiler driver), run it on a `NodeRuntime` with a `timeout` or `AbortSignal`: + +```ts +const emitted = await tools.compileSource({ sourceText }); + +const rt = await NodeRuntime.create(); +try { + const out = await rt.exec(emitted.outputText ?? "", { + timeout: 5_000, + signal: AbortSignal.timeout(10_000), + }); + console.log(out.exitCode); +} finally { + await rt.dispose(); +} +``` + +On timeout or abort the guest process is killed inside the VM, so a runaway compile can never hang the host. \ No newline at end of file diff --git a/website/public/docs/docs/nodejs-compatibility.md b/website/public/docs/docs/nodejs-compatibility.md new file mode 100644 index 000000000..d6cf3f3c6 --- /dev/null +++ b/website/public/docs/docs/nodejs-compatibility.md @@ -0,0 +1,135 @@ +# Node.js Compatibility + +Which node builtins guest code can import in Secure Exec, and how each one is backed. + +Guest code in Secure Exec runs as Node.js. It never touches the host runtime: every guest `import`/`require` of a `node:` builtin resolves to a kernel-backed bridge or an in-isolate polyfill, never the real host module. This page describes which builtins are available and how each one is implemented. + +The guest reports itself as Node `v22.0.0` (`process.version`). + +## How builtins are backed + +There are three ways a builtin is provided to guest code: + +- **Bridge.** A kernel-backed implementation. Calls route through the kernel VFS, socket table, process table, DNS resolver, or host entropy. This is how `fs`, `net`, `http`, `child_process`, `dns`, `os`, and `crypto` reach virtualized resources while staying inside the isolation boundary. +- **Polyfill.** A pure-JavaScript implementation from `node-stdlib-browser` (for example `path`, `events`, `util`, `stream`, `zlib`). These need no host access; they run entirely inside the V8 isolate. +- **Denied.** The module is intentionally unavailable. Importing it throws an error with code `ERR_ACCESS_DENIED`. + +The canonical inventory lives in `crates/execution/assets/polyfill-registry.json`. + +A guest never falls through to a real host builtin. Anything not bridged or polyfilled is denied, so there is no path where guest code reaches the host runtime. + +## Bridge-backed builtins + +These route through the kernel and present normal Linux/Node semantics over virtualized resources. + +| Module | Backed by | +| --- | --- | +| `fs`, `fs/promises` | Kernel VFS. File and directory operations, fds, `createReadStream`/`createWriteStream`, metadata, symlinks. `watch`/`watchFile` are guest-side polling wrappers. | +| `child_process` | Kernel process table. `spawn`, `exec`, `execFile`, `spawnSync`, `execSync`, `execFileSync` (and the sync variants) run kernel-managed processes. See [Child Processes](/docs/features/child-processes). | +| `net` | Kernel socket table. TCP client and server sockets, plus Unix sockets. | +| `dns` | Kernel DNS resolver (`lookup`, `resolve*`, and the `dns/promises` surface). | +| `http`, `https`, `http2` | Built on the kernel socket path. `request`, `get`, `createServer`, agents with connection pooling. | +| `tls` | Layered on the kernel `net` polyfill. | +| `os` | VM-scoped values (platform, arch, hostname, CPU/memory, user info, `os.constants`). | +| `crypto` | Host entropy and crypto bridges: `getRandomValues`, `randomUUID`, `randomBytes`, `createHash`, `createHmac`, cipher/decipher, scrypt, and `crypto.subtle` (WebCrypto). | +| `process` | Virtualized `process` global: env (permission-gated), `cwd`/`chdir`, signals, timers, stdio, `umask`. | +| `module` | `createRequire`, `Module` basics, builtin resolution, `Module.builtinModules`. | +| `console` | Bridge shim with circular-safe formatting. Output is captured into the `stdout`/`stderr` result fields and can also be streamed via the `onStdout`/`onStderr` hooks on `exec`/`run`/`spawn`. | +| `dgram` | Kernel socket table (UDP). | +| `perf_hooks`, `diagnostics_channel`, `async_hooks` | Bridge-backed compatibility surfaces. | +| `worker_threads` | Compatibility shim: `isMainThread` and inert ports for feature detection. Real worker threads are not spawned. | +| `vm` | Compatibility shim: `Script`, `createContext`, `isContext`, `runInNewContext`, `runInThisContext`. | +| `v8` | Compatibility shim for safe inspection/serialization helpers. | +| `tty` | `isatty` plus `ReadStream`/`WriteStream` compatibility constructors. | +| `readline`, `sqlite` | Bridge-backed compatibility surfaces. | +| `timers`, `timers/promises` | `setTimeout`, `setInterval`, `setImmediate`, and promise variants. | +| `stream/web`, `stream/consumers`, `stream/promises` | Web Streams and stream helper subpaths. | + +Network builtins (`net`, `dgram`, `dns`, `http`, `https`, `http2`, `tls`) are subject to the per-runtime permission policy, which **denies network access by default**. Operations fail until you opt in. See [Permissions](/docs/features/permissions). + +## Polyfilled builtins + +Pure-JavaScript implementations from `node-stdlib-browser`, running inside the isolate. They support default and named ESM imports. + +| Module | Polyfill | +| --- | --- | +| `path`, `path/posix`, `path/win32` | `path-browserify` | +| `buffer` | `buffer` (also re-exports `Blob`/`File`) | +| `events` | `events` | +| `stream` | `readable-stream` | +| `util`, `util/types` | node-stdlib-browser | +| `assert` | node-stdlib-browser | +| `url` | node-stdlib-browser shims | +| `querystring` | node-stdlib-browser | +| `string_decoder` | node-stdlib-browser | +| `zlib` | node-stdlib-browser | +| `punycode` | node-stdlib-browser | +| `constants` | `constants-browserify` (`os.constants` stays available via `os`) | +| `console`, `timers` | node-stdlib-browser base, with bridge wiring for stdio and the kernel clock | +| `sys` | alias of `util` | + +## Denied builtins + +Importing any of these throws an error with code `ERR_ACCESS_DENIED`: + +`cluster`, `domain`, `inspector`, `repl`, `trace_events`, `wasi`. + +## Global APIs + +Web platform globals expected by modern npm packages are provided in the isolate, including `fetch`, `Headers`, `Request`, and `Response`. Guest `fetch()` runs through undici inside the V8 isolate and then through the kernel socket table, so it obeys the same network permissions as the `http`/`net` builtins. `TextEncoder`/`TextDecoder`, `Buffer`, `URL`/`URLSearchParams`, `Blob`/`File`, `FormData`, `AbortController`/`AbortSignal`, `structuredClone`, and `performance` are also available. + +WebAssembly is enabled inside the isolate (`WebAssembly.Module`, `WebAssembly.Instance`, `WebAssembly.instantiate*`), so packages that ship `.wasm` work. Compilation stays inside the isolate and does not cross the isolation boundary. + +## Restricting the builtin surface + +The builtin surface can be narrowed through the [platform / `allowedBuiltins` config](/docs/features/runtime-platform); anything excluded becomes a denied builtin (`ERR_ACCESS_DENIED`). + +This config (`CreateVmConfig.jsRuntime`) rides the wire `CreateVmConfig` and is not currently exposed through `NodeRuntime.create()`. See [Runtime Platform](/docs/features/runtime-platform) for the platform ladder and [TypeScript SDK](/docs/sdks/typescript) for the config shape. + +## Logging behavior + +- `console.log`/`warn`/`error` serialize arguments with circular-safe, bounded formatting. +- `exec()` and `run()` buffer guest output and return it as the `stdout` and `stderr` strings on the result. +- To observe output incrementally, pass the `onStdout`/`onStderr` hooks, which receive raw `Uint8Array` chunks in emission order; the full strings are still returned when the run ends. + +See [Output Capture](/docs/features/output-capture) for details. + +## TypeScript + +The core runtime executes JavaScript. For sandboxed TypeScript usage, see [TypeScript](/docs/features/typescript). + +## Example + +Import a mix of bridge-backed and polyfilled builtins from guest code: + +```ts +import { NodeRuntime } from "secure-exec"; + +const rt = await NodeRuntime.create(); + +try { + const { stdout } = await rt.exec(` + import path from "node:path"; + import { createHash } from "node:crypto"; + import { writeFileSync, readFileSync } from "node:fs"; + + const file = path.join("/tmp", "note.txt"); + writeFileSync(file, "hello"); + + const digest = createHash("sha256") + .update(readFileSync(file)) + .digest("hex"); + + console.log(digest); + `); + + console.log(stdout.trim()); +} finally { + await rt.dispose(); +} +``` + +## See also + +- **Module loading and resolution**: how ESM/CJS, the `node_modules` walk, and unmodified npm packages resolve over the virtual filesystem lives in [NPM & Module Loading](/docs/features/module-loading). +- **Output capture**: how `stdout`/`stderr` are buffered and streamed is documented in [Output Capture](/docs/features/output-capture). \ No newline at end of file diff --git a/website/public/docs/docs/quickstart.md b/website/public/docs/docs/quickstart.md new file mode 100644 index 000000000..00ac38211 --- /dev/null +++ b/website/public/docs/docs/quickstart.md @@ -0,0 +1,71 @@ +# Quickstart + +Get Secure Exec running in a few minutes. + +1. **Install** + + ```bash title="npm" + npm install secure-exec + ``` + + ```bash title="bun" + bun add secure-exec + ``` + + ```bash title="pnpm" + pnpm add secure-exec + ``` + + ```bash title="yarn" + yarn add secure-exec + ``` + +2. **Create a runtime** + + `NodeRuntime.create()` boots a fully virtualized VM behind the native sidecar. Guest code runs inside the kernel isolation boundary with no host escapes. All options are optional: `cwd` defaults to `/workspace`, and permissions default to a secure policy that denies network access (see step 4). + + ```ts + import { NodeRuntime } from "secure-exec"; + + const runtime = await NodeRuntime.create(); + ``` + +3. **Run code** + + Use `run()` when you want a JSON value back; the guest calls `globalThis.__return(value)` to set it. Use `exec()` when you care about side effects and want to capture `stdout`/`stderr`/`exitCode`. Guest code runs as an ES module, so `import` and top-level `await` both work. + + ```ts title="Capture output" + import { NodeRuntime } from "secure-exec"; + + const runtime = await NodeRuntime.create(); + + try { + // exec() runs guest code for its side effects and captures the streams. + const result = await runtime.exec(` + console.log("hello from secure-exec"); + console.error("this goes to stderr"); + `); + + console.log("stdout:", JSON.stringify(result.stdout.trim())); + console.log("stderr:", JSON.stringify(result.stderr.trim())); + console.log("exitCode:", result.exitCode); + } finally { + await runtime.dispose(); + } + ``` + + *[See Full Example](https://github.com/rivet-dev/secure-exec/tree/main/examples/docs/quickstart)* + +4. **Configure permissions (optional)** + + Guest code is **deny-by-default** for network access. Pass a `permissions` policy to `NodeRuntime.create()` to opt in; it merges over the secure default, so you only specify what you want to change: + + ```ts + const runtime = await NodeRuntime.create({ + permissions: { network: "allow" }, + }); + ``` + + See [Permissions](/docs/features/permissions) for the full scope list and merge semantics. + +## Next steps \ No newline at end of file diff --git a/website/public/docs/docs/sdks/rust.md b/website/public/docs/docs/sdks/rust.md new file mode 100644 index 000000000..8d10e57e0 --- /dev/null +++ b/website/public/docs/docs/sdks/rust.md @@ -0,0 +1,22 @@ +# Rust SDK + +Install the Secure Exec Rust client and find its generated docs.rs reference. + +The `secure-exec-client` crate is the Rust SDK. It speaks the same sidecar wire protocol as the TypeScript client, so every capability reachable from `secure-exec` is also reachable from Rust through `SidecarProcess`. + +## Install + +```bash +cargo add secure-exec-client +``` + +Or add it to `Cargo.toml`: + +```toml +[dependencies] +secure-exec-client = "*" +``` + +## API reference + +The full reference is generated with rustdoc and published to docs.rs. Use it as the source of truth for signatures and types. \ No newline at end of file diff --git a/website/public/docs/docs/sdks/typescript.md b/website/public/docs/docs/sdks/typescript.md new file mode 100644 index 000000000..3769abac5 --- /dev/null +++ b/website/public/docs/docs/sdks/typescript.md @@ -0,0 +1,27 @@ +# TypeScript SDK + +Install the Secure Exec TypeScript SDK and find its generated API reference. + +The `secure-exec` package is the TypeScript SDK. It exports `NodeRuntime`, the batteries-included entry point for booting a virtualized VM and running guest JavaScript, plus the types describing its options and results. + +## Install + +```bash +npm install secure-exec +``` + +```ts +import { NodeRuntime } from "secure-exec"; + +const rt = await NodeRuntime.create(); +try { + const { stdout } = await rt.exec("console.log('hi', 1 + 1)"); + console.log(stdout); +} finally { + await rt.dispose(); +} +``` + +## API reference + +The full type-level reference is generated from the source with TypeDoc and is the source of truth for every export, method, and option. \ No newline at end of file diff --git a/website/public/docs/docs/security-model.md b/website/public/docs/docs/security-model.md new file mode 100644 index 000000000..ff93817b1 --- /dev/null +++ b/website/public/docs/docs/security-model.md @@ -0,0 +1,14 @@ +# Security Model + +A short overview of Secure Exec isolation and trust, with a link to the canonical agentOS security model. + +Secure Exec runs guest code inside a fully virtualized VM so untrusted code stays contained. At a glance: + +- **V8 isolate boundary**: Guest JavaScript runs in a V8 isolate inside the kernel. It never spawns a real host process, touches the real host filesystem, or opens a real host socket. +- **Sidecar enforces**: A trusted sidecar owns the kernel, VFS, socket table, and permission policy. Every guest syscall is mediated and checked there, not on the host. +- **Executor is untrusted**: The code you submit for execution is treated as actively hostile. How it reached the executor never makes it trusted. +- **Secure defaults**: The network is deny-by-default; filesystem, child processes, process info, and env are enabled so normal programs run. Resource and timing limits bound runaway or hostile code. + +## Full reference + +The canonical threat model, trust boundaries, and detailed enforcement guarantees are owned by agentOS. \ No newline at end of file diff --git a/website/public/docs/docs/use-cases/ai-agent-code-exec.md b/website/public/docs/docs/use-cases/ai-agent-code-exec.md new file mode 100644 index 000000000..fccad4da3 --- /dev/null +++ b/website/public/docs/docs/use-cases/ai-agent-code-exec.md @@ -0,0 +1,44 @@ +# AI Agent Code Exec + +Give AI agents a secure code-execution tool that runs untrusted code in a sandbox and returns structured results. + +Give your agent a code-execution tool that runs untrusted, model-generated code in a fully virtualized VM. The agent writes code, it runs inside the kernel isolation boundary with no access to the host, and you get back its stdout and a structured return value. + +## Run untrusted JavaScript and capture a result + +`NodeRuntime.create()` boots a sandboxed VM. `rt.run()` executes the guest code and decodes whatever it passes to `globalThis.__return()`, while still capturing `stdout`, `stderr`, and `exitCode`. Use `rt.exec()` when you only need the captured output streams. + +The guest code runs as a standard ES module (top-level `await` and `import` work), but it can only see the virtual filesystem and kernel-mediated syscalls, and it cannot reach the host machine. + +*[See Full Example](https://github.com/rivet-dev/secure-exec/tree/main/examples/docs/uc-ai-agent-code-exec)* + +Running this prints the captured stdout and the decoded return value, and shows that the guest only ever sees the sandbox: + +``` +exitCode: 0 +stdout: computed 20 fibonacci numbers +returned value: {"fibonacci":[0,1,1,2,3,5,8,13,21,34,55,89,144,233,377,610,987,1597,2584,4181],"sum":10945} + +escape attempt exitCode: 0 +escape attempt stdout: guest hostname: secure-exec +``` + +## Wiring it into an agent tool + +A single `NodeRuntime` instance can run many programs. Each `run()` / `exec()` call executes a fresh guest process. To expose this as a tool to your agent framework, hold one runtime for the session and call `rt.run(code)` from the tool's handler, returning `{ stdout, value, exitCode }` to the model. Pass a `timeout` (in milliseconds) per call to bound runaway code, and call `rt.dispose()` when the session ends. + +## Sandboxing untrusted code + +`NodeRuntime.create()` denies network by default and allows the virtualized `fs`, `childProcess`, `process`, and `env` scopes; any `permissions` you pass merges over that default, so an omitted scope keeps its default rather than being denied. Pass a partial policy (for example `{ network: "allow" }` to opt into the network, or a rule set on `fs` to tighten filesystem access) to adjust individual scopes. + +```ts +import { NodeRuntime } from "secure-exec"; + +// network is already denied by default; this opts it back in while the other +// scopes keep their defaults. +const rt = await NodeRuntime.create({ + permissions: { network: "allow" }, +}); +``` + +You can also constrain the run with `env` and `cwd` on `NodeRuntime.create()`, and `env`, `cwd`, `stdin`, and `timeout` on each `run()` / `exec()` call. \ No newline at end of file diff --git a/website/public/docs/docs/use-cases/code-mode.md b/website/public/docs/docs/use-cases/code-mode.md new file mode 100644 index 000000000..c451a09e3 --- /dev/null +++ b/website/public/docs/docs/use-cases/code-mode.md @@ -0,0 +1,61 @@ +# Code Mode (MCP) + +Give AI agents a single code-execution tool instead of individual MCP tools. The LLM writes code that chains binding calls, executed safely in Secure Exec. + +Instead of calling MCP tools one at a time, Code Mode lets the LLM write JavaScript that orchestrates everything in one go, run safely in a V8 sandbox by Secure Exec. + + [MCP Toolkit](https://mcp-toolkit.nuxt.dev/advanced/code-mode) provides a premade Code Mode library powered by Secure Exec: `experimental_codeMode: true`. We recommend trying it first. The rest of this page covers how to implement Code Mode yourself. + +## Why Code Mode + +- **[81% less token overhead](https://x.com/hugorcd/status/2034616192225407273)**: With 50 tools, replacing per-call tool descriptions with a single code-execution tool cuts tool description tokens by 81% +- **Fewer round-trips**: Chain multiple tool calls, conditionals, and data transformations in a single execution +- **Real control flow**: Loops, branching, and `Promise.all`, not a chain of isolated tool calls +- **One structured result**: The LLM returns a single JSON value via `globalThis.__return()`, decoded on the host as `result.value` + +## How it works + +1. Register your host bindings on the host with `NodeRuntime.create({ bindings })`. Each becomes a named command inside the sandbox. +2. Give the LLM one tool ("execute code") and feed its generated JavaScript to `rt.run()`. +3. The generated code invokes your bindings by name. Each call round-trips out of the sandbox, runs the binding's host `handler`, and the handler's return value comes back to the guest. +4. The guest hands a single structured result back to the host with `globalThis.__return(value)`, which `rt.run()` decodes as `result.value`. + +Host bindings are the heart of Code Mode. The handlers run on the host, never in the sandbox, so the guest gets controlled, named capabilities (the kind an AI agent calls as tools) without being granted the underlying access. Registering bindings auto-grants the `binding` permission scope; pass your own `permissions.binding` policy to gate individual bindings. + +## Register the host bindings + +Each binding has a `description`, a JSON Schema `inputSchema`, and a `handler`. The handler receives the parsed input and returns a JSON-serializable result. + +## The agent's generated code + +The agent then generates code like this (call it `llmGeneratedCode`). The guest calls each binding with the `callBinding(name, input)` global, which resolves with the host handler's return value. It chains three binding calls with real control flow (`Promise.all`, arithmetic, branching) in one execution, then returns a single structured result: + +## Run it and read the result + +Run the LLM's code in one sandboxed pass and read back the structured result: + +Three tool calls, one sandbox execution, zero extra LLM round-trips. Running it prints: + +```text +exitCode: 0 +stdout: chained 3 binding calls in one sandbox execution +structured result: { + "san_francisco": { + "temp_f": 61 + }, + "tokyo": { + "temp_f": 75 + }, + "difference": { + "fahrenheit": 14, + "celsius": 7.777777777777778 + }, + "warmer": "Tokyo" +} +``` + +## Further reading + +- [Complete Code Mode implementation guide](https://mcp-toolkit.nuxt.dev/advanced/code-mode): end-to-end Code Mode walkthrough using MCP Toolkit +- [Cloudflare Code Mode blog post](https://blog.cloudflare.com/code-mode/) +- [AI Agent Code Exec](/use-cases/ai-agent-code-exec) for simpler single-tool execution patterns \ No newline at end of file diff --git a/website/public/docs/docs/use-cases/dev-servers.md b/website/public/docs/docs/use-cases/dev-servers.md new file mode 100644 index 000000000..8b67f502e --- /dev/null +++ b/website/public/docs/docs/use-cases/dev-servers.md @@ -0,0 +1,95 @@ +# Dev Servers + +Run user-provided server-style code (HTTP servers, request handlers) inside a secure isolate. + +Let users run their own server-style code inside a sandboxed isolate. A guest program can boot a real `node:http` server, bind a loopback port owned by the kernel, and serve requests, all without touching the host machine. + +Secure Exec keeps a guest server running and forwards host requests into it. `spawn()` starts a long-running guest program and returns a process handle immediately, without waiting for it to exit. `fetch(port, { method, path, headers, body })` drives an HTTP request from the host into the guest server listening on that port, through the kernel socket table, and returns the response. The request and response never leave the VM, so this works even when guest network egress is denied. + +## Spawn a server and drive host requests into it + +The guest boots an HTTP server on loopback and stays alive serving requests. The host spawns it, blocks on `waitForListener()` until the server is accepting connections, drives a request into it, then kills the process and waits for it to exit. + +```ts +import { NodeRuntime } from "secure-exec"; + +// A user's "dev server": untrusted, long-running server-style code. It boots a +// real node:http server and keeps serving until it is killed, all inside the +// secure-exec VM with no access to the host machine. +const devServer = ` +import http from "node:http"; + +// Start the user's server, exactly as they wrote it. +const app = http.createServer((req, res) => { + if (req.url === "/health") { + res.writeHead(200, { "content-type": "application/json" }); + res.end(JSON.stringify({ ok: true })); + return; + } + res.writeHead(200, { "content-type": "text/plain" }); + res.end("hello from the sandboxed dev server"); +}); + +// Listen on loopback inside the VM. The kernel owns this socket; it never +// touches a real host port. The process stays alive serving requests until the +// host kills it. +app.listen(3000, "127.0.0.1", () => { + console.log("server listening on 127.0.0.1:3000"); +}); +`; + +// The guest binds a loopback port, so opt in to networking. NodeRuntime.create() +// denies network by default; permissions merge over that secure default. +const runtime = await NodeRuntime.create({ permissions: { network: "allow" } }); + +try { + // spawn() starts the server as a long-running guest process and returns a + // handle immediately, without waiting for it to exit. + const server = await runtime.spawn(devServer, { + onStdout: (chunk) => process.stdout.write(new TextDecoder().decode(chunk)), + }); + console.log("spawned guest server, pid:", server.pid); + + try { + // Block until the guest is actually accepting connections on the port, + // then drive requests into it. + await runtime.waitForListener({ port: 3000 }); + + // Drive a real host->guest request into the running server. + const health = await runtime.fetch(3000, { path: "/health" }); + console.log("health check ->", health.status, JSON.stringify(health.body)); + + const res = await runtime.fetch(3000, { method: "GET", path: "/" }); + console.log("GET / ->", res.status, JSON.stringify(res.body)); + + console.log( + "RESULT " + JSON.stringify({ status: res.status, body: res.body }), + ); + } finally { + // Tear the server down and wait for the guest process to exit. + server.kill(); + await server.wait(); + console.log("server stopped"); + } +} finally { + // Tear down the VM and release the sidecar. + await runtime.dispose(); +} +``` + +*[See Full Example](https://github.com/rivet-dev/secure-exec/tree/main/examples/docs/uc-dev-servers)* + +Running it spawns the server, drives host requests into it, and tears it down: + +``` +spawned guest server, pid: 1000000 +server listening on 127.0.0.1:3000 +health check -> 200 "{\"ok\":true}" +GET / -> 200 "hello from the sandboxed dev server" +RESULT {"status":200,"body":"hello from the sandboxed dev server"} +server stopped +``` + +The guest owns the server process, the application code, and the loopback socket, while the host stays in control of the lifecycle through the process handle (`kill()`, `wait()`) and `dispose()`. The kernel mediates the socket, so the guest never binds a real host port. + +This is useful for platforms that let users write and preview server-side code (live coding environments, serverless playgrounds, educational tools) without giving them access to the host machine. \ No newline at end of file diff --git a/website/public/docs/docs/use-cases/plugin-systems.md b/website/public/docs/docs/use-cases/plugin-systems.md new file mode 100644 index 000000000..4c6e713b0 --- /dev/null +++ b/website/public/docs/docs/use-cases/plugin-systems.md @@ -0,0 +1,63 @@ +# Plugin Systems + +Run user-authored plugins in isolation with explicit permissions. + +Let users upload scripts or extensions without risking your host. The host controls what plugin code runs, what capabilities are available, and what structured data comes back. + +## Run a plugin in isolation + +The host owns the plugin source and the input. Run the plugin with `run()` inside a sandboxed VM and get a structured value back: the guest calls `globalThis.__return(value)` with any JSON-serializable value, and that value is decoded on the host as `result.value`. + +The plugin below gets filesystem access but no network access. The guest proves it cannot reach the network, then transforms the host-supplied input. + +The plugin executes inside the kernel isolation boundary with only the capabilities you granted (network access is denied here), and the host gets back structured data via `__return()` rather than direct access to plugin internals. + +You can combine this with [TypeScript](/docs/features/typescript) to type-check uploaded plugin code before enabling it. + +## Let plugins call curated host tools + +Denying a capability outright is one option, but most plugin systems need the opposite: the plugin must reach a few host capabilities, just not the raw underlying access. The canonical pattern is host tools. You register a narrow set of named tools whose handlers run on the host, and the untrusted plugin invokes them by name. The plugin never gets the database connection, the secret, or the network socket behind the tool; it only gets the curated surface you chose to expose. + +Register host tools with the `tools` option on `create()` (or add them to a live runtime with `rt.registerTools()`). Each tool becomes a named command inside the VM, and the plugin invokes it with the `callHostTool(name, input)` global, which resolves with the host handler's return value. + +```ts Host Tools +import { NodeRuntime } from "secure-exec"; + +// Register curated host tools. Their handlers run on the host, so the plugin +// reaches these capabilities only through the tool surface you expose - never +// the underlying database, secrets, or network behind them. +const runtime = await NodeRuntime.create({ + tools: { + lookupUser: { + description: "Look up a user by id", + inputSchema: { + type: "object", + properties: { id: { type: "string" } }, + required: ["id"], + }, + // Runs on the host. In a real system this would hit your database. + handler: ({ id }: { id: string }) => ({ + id, + name: id === "u_1" ? "Ada Lovelace" : "Unknown", + }), + }, + }, +}); + +try { + // The untrusted plugin reaches the host capability only through callHostTool, + // which resolves with the handler's return value. + const { value } = await runtime.run<{ id: string; name: string }>(` + const user = await callHostTool("lookupUser", { id: "u_1" }); + __return(user); + `); + + console.log("looked-up user:", value?.name); +} finally { + await runtime.dispose(); +} +``` + +This is safe because the plugin reaches host capability only through the curated tool surface, never the underlying access behind it. The `tool` permission scope gates invocation: when you pass `tools` and set no `tool` policy, the scope is granted so the registered tools are invocable, but you can supply your own `permissions.tool` policy to gate individual tools. + +See [Bindings](/docs/features/bindings) for the full guide, including input schemas, command aliases, and worked examples. \ No newline at end of file diff --git a/website/public/fonts/jetbrains-mono/JetBrainsMono-Variable-latin.woff2 b/website/public/fonts/jetbrains-mono/JetBrainsMono-Variable-latin.woff2 new file mode 100644 index 0000000000000000000000000000000000000000..c3f0666ea8d891e46b1710f50c998eaa9b701fd5 GIT binary patch literal 40480 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 literal 0 HcmV?d00001 diff --git a/website/public/fonts/manrope/Manrope-Variable-latin.woff2 b/website/public/fonts/manrope/Manrope-Variable-latin.woff2 new file mode 100644 index 0000000000000000000000000000000000000000..9d7abb17d323bff647995a94222b92b26a0fc93d GIT binary patch literal 24576 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 v%=2?SKkNhLp=^Ephf+&9*X
- Docs + Documentation Changelog
{!showLogo && (
- Docs + Documentation Changelog
)} @@ -116,7 +116,7 @@ export function Navigation() { className="block py-2.5 px-3 text-white/80 hover:text-white hover:bg-white/5 rounded-lg transition-colors font-medium" onClick={() => setMobileMenuOpen(false)} > - Docs + Documentation /docs/quickstart). export const collections = { - docs: defineCollection({ loader: docsLoader(), schema: docsSchema() }), + docs: defineCollection({ + loader: glob({ pattern: "**/*.{md,mdx}", base: "./src/content/docs" }), + schema: z + .object({ + title: z.string(), + description: z.string().optional(), + }) + .passthrough(), + }), }; diff --git a/website/src/content/docs/docs/architecture.mdx b/website/src/content/docs/docs/architecture.mdx index 23fd99935..c006ba2b0 100644 --- a/website/src/content/docs/docs/architecture.mdx +++ b/website/src/content/docs/docs/architecture.mdx @@ -2,7 +2,6 @@ title: Architecture description: A short overview of the Secure Exec architecture, with a link to the canonical agentOS architecture docs. --- -import { LinkCard } from '@astrojs/starlight/components'; Secure Exec runs untrusted guest code inside a fully virtualized VM whose kernel services every guest syscall. At a glance: @@ -15,8 +14,6 @@ Secure Exec runs untrusted guest code inside a fully virtualized VM whose kernel The canonical, in-depth architecture reference, including packages, crates, trust boundaries, and syscall paths, is owned by agentOS. - + + The complete architecture reference, including components, trust boundary, and syscall paths. + diff --git a/website/src/content/docs/docs/benchmarks.mdx b/website/src/content/docs/docs/benchmarks.mdx index 046503176..eaf687a8e 100644 --- a/website/src/content/docs/docs/benchmarks.mdx +++ b/website/src/content/docs/docs/benchmarks.mdx @@ -2,11 +2,10 @@ title: Benchmarks description: Cold start, warm execution, and reuse fast-path measurements for the Secure Exec SDK. --- -import { Aside } from '@astrojs/starlight/components'; These numbers measure the public `secure-exec` SDK paths that consumers actually use. The cold start matrix (`packages/benchmarks/coldstart.bench.ts`) times the full journey from booting a runtime to running guest code, and compares three ways of provisioning a runtime against how much you can reuse. - +Numbers below are a full run from June 19, 2026 on the hardware listed under [Methodology](#methodology). They are indicative at this sample count (5 iterations + 1 warmup), not statistically tight. Reproduce them with the commands in [Running the benchmarks](#running-the-benchmarks). ## Scenarios diff --git a/website/src/content/docs/docs/comparison/cloudflare-workers.mdx b/website/src/content/docs/docs/comparison/cloudflare-workers.mdx index e1840ddc6..89181e942 100644 --- a/website/src/content/docs/docs/comparison/cloudflare-workers.mdx +++ b/website/src/content/docs/docs/comparison/cloudflare-workers.mdx @@ -2,7 +2,6 @@ title: Secure Exec vs Cloudflare Workers description: How Secure Exec and Cloudflare Workers differ in isolation model, permissions, networking, and Node.js compatibility. --- -import { Aside, LinkCard } from '@astrojs/starlight/components'; Secure Exec and Cloudflare Workers both run untrusted JavaScript inside V8, but they solve different problems. Workers is a managed, multi-tenant edge platform: you deploy code and Cloudflare runs it for you across its network. Secure Exec is a library you embed in your own application to run guest code locally inside a fully virtualized VM that you control. This page focuses on how the two differ in isolation, permissions, networking, and Node.js surface. @@ -28,11 +27,9 @@ Secure Exec isolates code statically, one boundary per runtime. Every `NodeRunti Within a single runtime, every `exec()` or `run()` call runs in a fresh guest process, so in-memory state from one run does not leak into the next. - + + How runtimes and runs are isolated, and how to choose granularity. + The practical consequence: with Workers you trust Cloudflare's platform to keep tenants apart. With Secure Exec you get a hard, statically-defined boundary per runtime that you place yourself, which is well suited to running one tenant or one task per runtime and disposing it when finished. @@ -54,7 +51,7 @@ const networked = await NodeRuntime.create({ }); ``` - +The permission policy is merged over a secure default, so a partial policy like `{ network: "allow" }` works. See [Permissions](/docs/features/permissions) for rule-set syntax to gate individual scopes. ## Networking @@ -93,11 +90,9 @@ Secure Exec presents a virtualized POSIX environment. Guest code can use `node:c Cloudflare Workers has no subprocess model. There is no `child_process`, no process table, and no shell. - + + Spawn kernel-managed processes from guest code, or drive a long-running guest program from the host. + ## Node.js compatibility @@ -106,7 +101,7 @@ Both runtimes aim to present Node.js semantics on top of V8, and both implement - **Secure Exec** is backed by a real virtualized kernel, so capabilities that need an OS, a full filesystem, real child processes, sockets that listen, and a process table, are first-class. Pure-JS builtins are provided through `node-stdlib-browser`, and kernel-backed modules (such as `fs`, `net`, `child_process`, `dns`, `http`, `os`) are wired through the bridge to the kernel. - **Cloudflare Workers** provides Node.js compatibility through the `nodejs_compat` flag on top of `workerd`. Its filesystem is a limited in-memory surface, there is no subprocess support, and listening servers are replaced by the request/response handler model. In exchange it ships a comprehensive native `node:crypto` and Web Crypto surface and platform-native logging. - +Module support evolves on both sides. Treat the points above as the shape of the difference (kernel-backed POSIX vs managed edge isolate), not a frozen feature matrix. Verify a specific module against the current behavior of whichever runtime you target. ## When to choose which @@ -114,8 +109,6 @@ Choose **Cloudflare Workers** when you want a managed, globally distributed plat Choose **Secure Exec** when you need to run untrusted or AI-generated code inside your own application with a hard, self-placed isolation boundary, a real virtualized filesystem and process model, and a capability policy you control. One runtime per tenant or per task gives you a clean blast radius you can dispose on demand. - + + The isolation model in depth, plus how to pick isolation granularity. + diff --git a/website/src/content/docs/docs/comparison/isolated-vm.mdx b/website/src/content/docs/docs/comparison/isolated-vm.mdx index e40b089fa..b2c65e0e0 100644 --- a/website/src/content/docs/docs/comparison/isolated-vm.mdx +++ b/website/src/content/docs/docs/comparison/isolated-vm.mdx @@ -2,7 +2,6 @@ title: Secure Exec vs isolated-vm description: How Secure Exec and isolated-vm differ in isolation surface, security confinement, performance, and developer experience. --- -import { Aside, LinkCard } from '@astrojs/starlight/components'; Both Secure Exec and isolated-vm run untrusted JavaScript inside V8 isolates, but they operate at different layers. isolated-vm is a low-level npm library that exposes a bare V8 isolate with manual value marshaling and no system surface. Secure Exec wraps V8 isolates in a full virtualized kernel: a POSIX-like VFS, process table, socket table, permission policy, and resource limits. This page focuses on the security and performance characteristics of that core runtime layer. @@ -36,7 +35,7 @@ A bare V8 isolate confines memory and CPU, but it confines nothing else, because - **What Secure Exec confines**: in addition to memory and time, it enforces a deny-by-default capability policy over filesystem, network, child-process, process, and env scopes. A denied operation fails with `EACCES`. - **Egress control**: guest `fetch()`, `node:http`, and raw sockets flow through the kernel socket table, so outbound traffic can be allowed, denied, or rule-matched. With isolated-vm there is no networking until you build it, and once built it is not policed. - +With isolated-vm, a mistake in your marshaling layer (handing the guest a live host `Reference`, or an injected function that does unchecked I/O) is a sandbox escape. Secure Exec moves that boundary into a kernel so the surface the guest sees is virtualized rather than hand-wired per project. ```ts import { NodeRuntime } from "secure-exec"; @@ -50,11 +49,9 @@ const networked = await NodeRuntime.create({ }); ``` - + + The deny-by-default capability policy and per-scope rule sets. + ## Performance @@ -94,8 +91,6 @@ try { | **isolated-vm** | You want a minimal V8 isolate primitive and intend to design and own the entire sandbox surface, capability injection, and enforcement yourself. | | **Secure Exec** | You want to run untrusted or AI-generated code with a virtualized filesystem, process model, and networking, plus a deny-by-default permission policy and resource limits, without hand-building the sandbox. | - + + The isolation model in depth, plus how to pick isolation granularity. + diff --git a/website/src/content/docs/docs/comparison/quickjs.mdx b/website/src/content/docs/docs/comparison/quickjs.mdx index 9dfa72105..bd0ba8bcb 100644 --- a/website/src/content/docs/docs/comparison/quickjs.mdx +++ b/website/src/content/docs/docs/comparison/quickjs.mdx @@ -2,7 +2,6 @@ title: Secure Exec vs QuickJS description: How Secure Exec and QuickJS differ in isolation model, performance, language coverage, and system surface. --- -import { Aside, LinkCard } from '@astrojs/starlight/components'; Secure Exec and QuickJS both run guest JavaScript, but they sit at different layers. QuickJS is a small, embeddable JavaScript engine: you link it into a host process and call its C API. Secure Exec is a full virtualized runtime built on V8, with a kernel, virtual filesystem, and capability policy around the engine. This page focuses on the security and performance characteristics of the core runtime layer. @@ -26,11 +25,9 @@ This is the most important difference. The practical consequence: with QuickJS you own the entire sandbox, including the boundary, the permission checks, and the host-bindings audit surface. With Secure Exec the boundary, the kernel, and the policy enforcement are provided and run out-of-process. - + + How runtimes and runs are isolated, and how to choose granularity. + ## Performance @@ -41,7 +38,7 @@ The engines optimize for different things. For Secure Exec, cold start is dominated by bringing up the guest runtime rather than provisioning infrastructure, and reusing a live guest process drives warm execution into the low-millisecond range. - +Treat these as the shape of the difference (JIT throughput vs interpreter footprint), not fixed numbers. See [Benchmarks](/docs/benchmarks) for measured cold-start, warm, and reuse numbers and the methodology behind them. ## Language and ecosystem coverage @@ -53,11 +50,9 @@ For Secure Exec, cold start is dominated by bringing up the guest runtime rather - **Secure Exec** presents a virtualized POSIX environment to guest code: a per-runtime virtual filesystem, a kernel-managed process table (with `node:child_process`), a socket table for networking, pipes, and PTYs. Guest `fetch()`, `node:http`, and raw sockets all flow through the kernel and the permission policy. - **QuickJS** has none of this built in. The bare engine exposes only ECMAScript globals; there is no filesystem, no process model, no networking, and no shell unless your host code adds C bindings for them. Every capability the guest needs is host surface you write and must secure. - + + Spawn kernel-managed processes from guest code, or drive a long-running guest program from the host. + ## When to choose which @@ -65,8 +60,6 @@ Choose **QuickJS** when you need the smallest possible embeddable engine, you ar Choose **Secure Exec** when you need full ECMAScript and npm compatibility, JIT throughput, and a ready-made isolation boundary with a kernel-backed filesystem, process model, networking, and a deny-by-default capability policy you control. - + + The isolation model in depth, plus how to pick isolation granularity. + diff --git a/website/src/content/docs/docs/comparison/sandbox.mdx b/website/src/content/docs/docs/comparison/sandbox.mdx index b609dd5ba..45331ed12 100644 --- a/website/src/content/docs/docs/comparison/sandbox.mdx +++ b/website/src/content/docs/docs/comparison/sandbox.mdx @@ -2,7 +2,6 @@ title: Secure Exec vs Container Sandbox description: When to use a container sandbox versus Secure Exec for running untrusted code. --- -import { Aside } from '@astrojs/starlight/components'; Secure Exec and container sandboxes both run untrusted code in isolation, but they sit at different points on the weight-versus-flexibility curve. Picking the right one depends on what you need to run. @@ -58,11 +57,11 @@ These capabilities are the reason to reach for Secure Exec over a container when - You need a **persistent, long-lived** environment such as a multi-hour dev session. - The workload genuinely needs a real kernel and a real disk. - + ## A minimal example diff --git a/website/src/content/docs/docs/crash-course.mdx b/website/src/content/docs/docs/crash-course.mdx index a43207ea3..db5bc2dc7 100644 --- a/website/src/content/docs/docs/crash-course.mdx +++ b/website/src/content/docs/docs/crash-course.mdx @@ -3,8 +3,6 @@ title: Crash Course description: "A fast tour of Secure Exec: install, run code, capture output, and the core SDK concepts." --- -import { Tabs, TabItem } from '@astrojs/starlight/components'; - This is a fast, guided walk through the essentials: install the SDK, boot a runtime, run guest code, and capture its output. By the end you will understand the core loop and know where to go for more. @@ -17,26 +15,39 @@ For exact signatures and option shapes, see the ## Install - - ```bash - npm install secure-exec - ``` - - - ```bash - bun add secure-exec - ``` - - - ```bash - pnpm add secure-exec - ``` - - - ```bash - yarn add secure-exec - ``` - + + + +```bash +npm install secure-exec +``` + + + + + +```bash +bun add secure-exec +``` + + + + + +```bash +pnpm add secure-exec +``` + + + + + +```bash +yarn add secure-exec +``` + + + ## Your first run diff --git a/website/src/content/docs/docs/features/child-processes.mdx b/website/src/content/docs/docs/features/child-processes.mdx index ea9481159..429fa4f4a 100644 --- a/website/src/content/docs/docs/features/child-processes.mdx +++ b/website/src/content/docs/docs/features/child-processes.mdx @@ -2,7 +2,6 @@ title: Child Processes description: Spawn child processes from sandboxed code. --- -import { Aside, LinkCard } from '@astrojs/starlight/components'; Two ways to run processes in Secure Exec: @@ -13,38 +12,7 @@ Two ways to run processes in Secure Exec: Guest code uses the standard `node:child_process` module to spawn commands available in the VM (`sh`, `node`, and the mounted coreutils): -```ts -import { NodeRuntime } from "secure-exec"; - -const rt = await NodeRuntime.create(); - -try { - const { stdout, stderr, exitCode } = await rt.exec(` - import { execFileSync } from "node:child_process"; - - // Spawn a shell command and capture its stdout. - const shellOut = execFileSync("sh", ["-c", "echo hello from a child process"], { - encoding: "utf8", - }); - console.log("sh output:", shellOut.trim()); - - // Spawn node as a child process and read its version. - const nodeVersion = execFileSync("node", ["--version"], { - encoding: "utf8", - }); - console.log("child node version:", nodeVersion.trim()); - `); - - console.log("exitCode:", exitCode); - if (stderr.trim()) console.log("guest stderr:", stderr.trim()); - console.log("guest stdout:"); - console.log(stdout.trim()); -} finally { - await rt.dispose(); -} -``` - -*[See Full Example](https://github.com/rivet-dev/secure-exec/tree/main/examples/docs/feat-child-processes)* + Output: @@ -65,7 +33,7 @@ const rt = await NodeRuntime.create({ }); ``` - +Child processes always run inside the kernel. Guest code cannot reach a real host process or host binary; `node:child_process` only sees the commands the VM mounts. ### Where the commands come from diff --git a/website/src/content/docs/docs/features/executing-code.mdx b/website/src/content/docs/docs/features/executing-code.mdx index 28cdb93a5..7188b7a03 100644 --- a/website/src/content/docs/docs/features/executing-code.mdx +++ b/website/src/content/docs/docs/features/executing-code.mdx @@ -2,7 +2,6 @@ title: Executing Code description: Run guest JavaScript with exec() and run(), and return values from the sandbox. --- -import { LinkCard } from '@astrojs/starlight/components'; `exec()` and `run()` are the two ways to run guest code to completion. The code runs inside the VM as a standard ES module, so top-level `import` and top-level @@ -64,8 +63,20 @@ result shapes, see the [TypeScript SDK reference](/docs/sdks/typescript). ## Related - - - - - + + + The result shape and streaming stdout/stderr as it is produced. + + + Reuse a live guest process for low-latency repeated execution. + + + spawn() long-running guests and the guest child_process surface. + + + Bound a run with timeout, AbortSignal, and the VM's limits. + + + Register host-side tools the guest invokes by name. + + diff --git a/website/src/content/docs/docs/features/filesystem.mdx b/website/src/content/docs/docs/features/filesystem.mdx index ea7ed3415..26c9d006b 100644 --- a/website/src/content/docs/docs/features/filesystem.mdx +++ b/website/src/content/docs/docs/features/filesystem.mdx @@ -2,7 +2,6 @@ title: Filesystem description: A short overview of the Secure Exec filesystem, with a link to the canonical agentOS filesystem docs. --- -import { LinkCard } from '@astrojs/starlight/components'; Each VM presents a normal POSIX filesystem to guest code, backed by a virtual filesystem inside the kernel. At a glance: @@ -16,8 +15,6 @@ Each VM presents a normal POSIX filesystem to guest code, backed by a virtual fi The canonical filesystem API, including seeding files, host-boundary file exchange, and the full mount and backend configuration, is owned by agentOS. - + + The complete filesystem API plus mount and backend configuration details. + diff --git a/website/src/content/docs/docs/features/module-loading.mdx b/website/src/content/docs/docs/features/module-loading.mdx index d587e0cda..f5632c5d6 100644 --- a/website/src/content/docs/docs/features/module-loading.mdx +++ b/website/src/content/docs/docs/features/module-loading.mdx @@ -2,7 +2,6 @@ title: "NPM & Module Loading" description: How sandboxed code resolves and loads modules. --- -import { Aside } from '@astrojs/starlight/components'; Guest `import` and `require` resolve against the VM's virtual filesystem, never the host module loader. Resolution runs entirely inside the kernel. By default the guest sees an empty `node_modules`; project host packages into the VM with `nodeModules` (or `mounts`) to run real npm packages (including the TypeScript compiler) in-sandbox. @@ -12,42 +11,7 @@ Guest `import` and `require` resolve against the VM's virtual filesystem, never - Build a CommonJS `require` with `createRequire(import.meta.url)`. - Both paths resolve through the kernel's module loader. -```ts -import { NodeRuntime } from "secure-exec"; - -const rt = await NodeRuntime.create(); - -try { - const { stdout, stderr, exitCode } = await rt.exec(` - // ESM import of a Node builtin. - import { basename, join } from "node:path"; - - // CommonJS require, created from the current module URL. - import { createRequire } from "node:module"; - const require = createRequire(import.meta.url); - const os = require("node:os"); - - const resolved = { - basename: basename("/workspace/data/report.txt"), - joined: join("/workspace", "data", "report.txt"), - platform: os.platform(), - }; - - console.log("resolved node:path via import ->", resolved.joined); - console.log("resolved node:os via require ->", resolved.platform); - console.log(JSON.stringify(resolved)); - `); - - console.log("exitCode:", exitCode); - if (stderr.trim()) console.log("guest stderr:\n" + stderr.trim()); - console.log("guest stdout:"); - console.log(stdout.trim()); -} finally { - await rt.dispose(); -} -``` - -*[See Full Example](https://github.com/rivet-dev/secure-exec/tree/main/examples/docs/feat-module-loading)* + ``` exitCode: 0 @@ -57,7 +21,7 @@ resolved node:os via require -> linux {"basename":"report.txt","joined":"/workspace/data/report.txt","platform":"linux"} ``` - +Resolution runs inside the kernel against the guest's virtual filesystem. The guest only sees what is present there; mounting host `node_modules` (below) makes those packages part of that filesystem so they resolve like any other guest module. ## Loading real npm packages @@ -71,49 +35,7 @@ Either way the host filesystem is never exposed; the guest sees only the project The example below points `nodeModules` at the host directory that holds `is-number`, then imports it from inside the VM. The guest resolves it the way Node would over a real filesystem, including through `createRequire`. -```ts -import { fileURLToPath } from "node:url"; -import { NodeRuntime } from "secure-exec"; - -const hostNodeModules = fileURLToPath( - new URL("../../../../node_modules", import.meta.url), -); - -const mounted = await NodeRuntime.create({ - nodeModules: hostNodeModules, -}); - -try { - const { stdout, stderr, exitCode } = await mounted.exec(` - // ESM import of the real, host-mounted npm package. - import isNumber from "is-number"; - - // The same package also resolves through a CommonJS require. - import { createRequire } from "node:module"; - const require = createRequire(import.meta.url); - const isNumberCjs = require("is-number"); - - const result = { - "isNumber(42)": isNumber(42), - 'isNumber("3.14")': isNumber("3.14"), - 'isNumber("nope")': isNumber("nope"), - sameModule: isNumber === isNumberCjs, - }; - - console.log("loaded real npm package is-number"); - console.log(JSON.stringify(result)); - `); - - console.log("exitCode:", exitCode); - if (stderr.trim()) console.log("guest stderr:\n" + stderr.trim()); - console.log("guest stdout:"); - console.log(stdout.trim()); -} finally { - await mounted.dispose(); -} -``` - -*[See Full Example](https://github.com/rivet-dev/secure-exec/tree/main/examples/docs/feat-module-loading)* + ``` exitCode: 0 @@ -132,7 +54,7 @@ When a guest filesystem contains `node_modules`, the resolver matches naive Node No package-manager-specific heuristics: pnpm/yarn layouts resolve because the VFS exposes their symlinks, not because the resolver special-cases them. - +A `nodeModules` (or `mounts`) host mount confines reads to the mounted directory: symlinks are followed only while they stay **inside** the mount root. A single-project `npm`/`pnpm` install resolves fine because its symlinks (including the `.pnpm` store) live inside `node_modules`. A workspace/monorepo install is different: pnpm/yarn and `file:` deps symlink packages to the workspace root or an external store, **outside** the leaf `node_modules`. Those targets are not followed, and the guest import fails with `Cannot resolve module '': not found`. Fix it by pointing the mount at a directory that contains every symlink target (for example the workspace root, mounted at the guest path the program resolves from) instead of the leaf `node_modules`. ## Seeding files directly diff --git a/website/src/content/docs/docs/features/networking.mdx b/website/src/content/docs/docs/features/networking.mdx index ffa806728..a9da68f91 100644 --- a/website/src/content/docs/docs/features/networking.mdx +++ b/website/src/content/docs/docs/features/networking.mdx @@ -2,7 +2,6 @@ title: Networking description: A short overview of Secure Exec networking, with a link to the canonical agentOS networking docs. --- -import { LinkCard } from '@astrojs/starlight/components'; Secure Exec virtualizes all VM networking so guest code never touches the real host network. At a glance: @@ -15,8 +14,6 @@ Secure Exec virtualizes all VM networking so guest code never touches the real h The canonical networking API, permission rules, and egress details are owned by agentOS. - + + The complete networking API, permission rules, and egress configuration. + diff --git a/website/src/content/docs/docs/features/output-capture.mdx b/website/src/content/docs/docs/features/output-capture.mdx index d52f1908a..188bcb7cd 100644 --- a/website/src/content/docs/docs/features/output-capture.mdx +++ b/website/src/content/docs/docs/features/output-capture.mdx @@ -11,27 +11,7 @@ description: Capture console output from sandboxed code. ## Capturing output -```ts -import { NodeRuntime } from "secure-exec"; - -const rt = await NodeRuntime.create(); - -try { - const { stdout, stderr, exitCode } = await rt.exec(` - console.log("hello from the sandbox"); - console.error("oops from the sandbox"); - process.exit(3); - `); - - console.log("exitCode:", exitCode); - console.log("stdout:", JSON.stringify(stdout)); - console.log("stderr:", JSON.stringify(stderr)); -} finally { - await rt.dispose(); -} -``` - -*[See Full Example](https://github.com/rivet-dev/secure-exec/tree/main/examples/docs/feat-output-capture)* + Prints: diff --git a/website/src/content/docs/docs/features/permissions.mdx b/website/src/content/docs/docs/features/permissions.mdx index 932427aee..ceba18b8f 100644 --- a/website/src/content/docs/docs/features/permissions.mdx +++ b/website/src/content/docs/docs/features/permissions.mdx @@ -2,7 +2,6 @@ title: Permissions description: A short overview of Secure Exec permissions, with a link to the canonical agentOS permissions docs. --- -import { LinkCard } from '@astrojs/starlight/components'; Secure Exec checks a per-domain permission policy against every guest syscall, so denied operations are rejected before any host resource is touched. At a glance: @@ -16,8 +15,6 @@ Secure Exec checks a per-domain permission policy against every guest syscall, s The complete permission scopes, modes, and rule configuration are owned by agentOS. - + + The complete permission scopes, modes, and rule configuration. + diff --git a/website/src/content/docs/docs/features/resident-runner.mdx b/website/src/content/docs/docs/features/resident-runner.mdx index 8225b2d29..f1b5debdd 100644 --- a/website/src/content/docs/docs/features/resident-runner.mdx +++ b/website/src/content/docs/docs/features/resident-runner.mdx @@ -2,7 +2,6 @@ title: Resident Runner description: Reuse a live guest process for low-latency repeated execution. --- -import { Aside, LinkCard } from '@astrojs/starlight/components'; Each `exec()` / `run()` call starts a fresh guest process, which is the right default for isolation between runs. When you run many small snippets against the @@ -10,11 +9,11 @@ same runtime (an evaluation loop, a REPL, a test harness), that per-run process startup dominates. A resident runner keeps one guest process alive and evaluates each snippet in it, so repeated calls are fast. - + ## Creating and using a runner @@ -48,4 +47,6 @@ runner when the same runtime runs many small snippets and the snippets are trusted to share a process. See the measured difference in [Benchmarks](/docs/benchmarks). - + +createResidentRunner() and the NodeRuntimeResidentRunner handle. + diff --git a/website/src/content/docs/docs/features/resource-limits.mdx b/website/src/content/docs/docs/features/resource-limits.mdx index 1eb773b24..d9503f914 100644 --- a/website/src/content/docs/docs/features/resource-limits.mdx +++ b/website/src/content/docs/docs/features/resource-limits.mdx @@ -2,7 +2,6 @@ title: Resource Limits description: Secure Exec resource limits, defaults, backpressure constants, and warning names. --- -import { LinkCard } from '@astrojs/starlight/components'; Secure Exec bounds each VM with per-VM resource caps so untrusted guest code can never exhaust the host. At a glance: @@ -256,8 +255,8 @@ CPU budgets therefore emit both the ~80% approach warning *and* a terminal exhau agentOS layers its own session and adapter limits on top of Secure Exec. - + + + The complete set of per-VM resource limits, defaults, and configuration options. + + diff --git a/website/src/content/docs/docs/features/runtime-platform.mdx b/website/src/content/docs/docs/features/runtime-platform.mdx index 529e5b8c0..8cbd0e8db 100644 --- a/website/src/content/docs/docs/features/runtime-platform.mdx +++ b/website/src/content/docs/docs/features/runtime-platform.mdx @@ -2,7 +2,6 @@ title: Runtime & Platform description: Customize the host environment guest code sees (the full Node.js surface today), plus the platform ladder (node, browser, neutral, bare) the kernel models. --- -import { LinkCard } from '@astrojs/starlight/components'; `NodeRuntime.create()` shapes the host environment guest code sees before it boots, and the kernel models that environment as a ladder of platforms (`node`, @@ -14,42 +13,7 @@ This page covers the customization surface: seeding and selecting the host environment, then the `moduleResolution` and `allowedBuiltins` knobs the wire config exposes. Start by probing the default `node` surface: -```ts -import { NodeRuntime } from "secure-exec"; - -const rt = await NodeRuntime.create(); - -try { - const probe = await rt.run<{ - platform: string; - hasProcess: boolean; - hasBuffer: boolean; - nodeVersion: string; - sha256: string; - joinedPath: string; - }>(` - const { createHash } = await import("node:crypto"); - const { join } = await import("node:path"); - - const sha256 = createHash("sha256").update("secure-exec").digest("hex"); - - globalThis.__return({ - platform: typeof process !== "undefined" ? process.platform : "(no process)", - hasProcess: typeof process !== "undefined", - hasBuffer: typeof Buffer !== "undefined", - nodeVersion: typeof process !== "undefined" ? process.versions.node : "(none)", - sha256, - joinedPath: join("/home/agentos", "report.txt"), - }); - `); - - console.log(probe.value); -} finally { - await rt.dispose(); -} -``` - -*[See Full Example](https://github.com/rivet-dev/secure-exec/tree/main/examples/docs/feat-runtime-platform)* + Output, the guest host environment as seen from inside the isolate: @@ -64,13 +28,14 @@ Output, the guest host environment as seen from inside the isolate: } ``` -:::note[Guest `run()` and `exec()` code both run as ES modules] -Both `rt.run()` and `rt.exec()` write your code into an `.mjs` module, so -top-level `import` and top-level `await` work in either. `run()` injects a -`globalThis.__return(value)` helper you call to hand a JSON-serializable value -back to the host (delivered as `result.value`); the example uses dynamic -`await import("node:…")` purely to keep the snippet a single expression body. -::: + +**Guest `run()` and `exec()` code both run as ES modules.** Both `rt.run()` and +`rt.exec()` write your code into an `.mjs` module, so top-level `import` and +top-level `await` work in either. `run()` injects a `globalThis.__return(value)` +helper you call to hand a JSON-serializable value back to the host (delivered as +`result.value`); the example uses dynamic `await import("node:…")` purely to keep +the snippet a single expression body. + ## Host environment (the `node` surface) @@ -148,11 +113,9 @@ For the full set of run methods (`exec`/`run`/`spawn`/`fetch`/`waitForListener`) and their per-run options (`env`, `cwd`, `stdin`, `timeout`, `signal`, `onStdout`/`onStderr`), see the TypeScript SDK reference: - + +Full signatures for exec/run/spawn/fetch/waitForListener and the shared per-run options. + ## The platform ladder @@ -179,16 +142,16 @@ in Secure Exec** (see the note below). `WebAssembly` stays available on **every tier**, including `bare`. Compilation happens inside the isolate and is not a host escape. -:::caution[Platform selection is not configurable in Secure Exec yet] -The kernel's wire protocol carries a `jsRuntime` config with `platform`, -`moduleResolution`, and `allowedBuiltins` fields. The tiers are -real in the kernel, but `NodeRuntime.create()` does **not** plumb those fields -through: it always boots the VM on the `node` platform with full Node module -resolution. There is no `NodeRuntime.create()` option to select -`browser`/`neutral`/`bare`, change module resolution, or restrict the builtin -allow-list today. The sections below document the intended model for those fields, -not a `create()` option you can pass. -::: + +**Platform selection is not configurable in Secure Exec yet.** The kernel's wire +protocol carries a `jsRuntime` config with `platform`, `moduleResolution`, and +`allowedBuiltins` fields. The tiers are real in the kernel, but +`NodeRuntime.create()` does **not** plumb those fields through: it always boots +the VM on the `node` platform with full Node module resolution. There is no +`NodeRuntime.create()` option to select `browser`/`neutral`/`bare`, change module +resolution, or restrict the builtin allow-list today. The sections below document +the intended model for those fields, not a `create()` option you can pass. + ## `moduleResolution`: how imports resolve @@ -246,8 +209,6 @@ subpaths), while `import("node:child_process")` is rejected. Omitting platforms deny all `node:*` builtins regardless, and unknown builtin names are rejected. - + +The complete jsRuntime config (platform, moduleResolution, allowedBuiltins) and the rest of CreateVmConfig. + diff --git a/website/src/content/docs/docs/features/typescript.mdx b/website/src/content/docs/docs/features/typescript.mdx index dc9ae3117..5742fea11 100644 --- a/website/src/content/docs/docs/features/typescript.mdx +++ b/website/src/content/docs/docs/features/typescript.mdx @@ -15,72 +15,7 @@ npm install @secure-exec/typescript secure-exec ## Compile and type-check a source string -```ts -import { createTypeScriptTools } from "@secure-exec/typescript"; -import { NodeRuntime } from "secure-exec"; - -const tools = createTypeScriptTools(); - -const typeScriptSource = ` -interface Greeting { - name: string; - count: number; -} - -const greeting: Greeting = { name: "secure-exec", count: 3 }; -const lines: string[] = Array.from( - { length: greeting.count }, - (_unused, index) => \`hello \${greeting.name} #\${index + 1}\`, -); - -for (const line of lines) { - console.log(line); -} -`; - -// Step 1: compile TypeScript to JavaScript inside the sandbox. -const compiled = await tools.compileSource({ - sourceText: typeScriptSource, - compilerOptions: { module: "ESNext", target: "ES2022" }, -}); - -if (!compiled.success) { - const messages = compiled.diagnostics.map((d) => d.message); - throw new Error(`TypeScript compile failed:\n${messages.join("\n")}`); -} - -console.log("Compiled TypeScript to JavaScript inside the sandbox."); - -// Step 2: run the emitted JavaScript inside the sandbox. -const rt = await NodeRuntime.create(); -try { - const result = await rt.exec(compiled.outputText ?? ""); - console.log("exitCode:", result.exitCode); - console.log("guest stdout:\n" + result.stdout.trimEnd()); -} finally { - await rt.dispose(); -} - -// Step 3: type-check a snippet that has a type error inside the sandbox. -const typeCheck = await tools.typecheckSource({ - sourceText: `const total: number = "not a number";`, -}); - -console.log("type check success:", typeCheck.success); -for (const diagnostic of typeCheck.diagnostics) { - console.log( - ` ${diagnostic.category} TS${diagnostic.code} (line ${diagnostic.line}): ${diagnostic.message}`, - ); -} - -if (typeCheck.success) { - throw new Error("Expected the ill-typed snippet to fail type checking."); -} - -console.log("OK: TypeScript compiled and type-checked inside the sandbox."); -``` - -*[See Full Example](https://github.com/rivet-dev/secure-exec/tree/main/examples/docs/feat-typescript)* + Prints: diff --git a/website/src/content/docs/docs/index.mdx b/website/src/content/docs/docs/index.mdx index 337b69255..fa4e52d14 100644 --- a/website/src/content/docs/docs/index.mdx +++ b/website/src/content/docs/docs/index.mdx @@ -1,9 +1,7 @@ --- title: Introduction description: 'Secure Exec: a fully virtualized runtime for executing untrusted code with zero host escapes.' -tableOfContents: false --- -import DocsLanding from '@rivet-dev/docs-theme/components/DocsLanding.astro'; - - +A lightweight library for secure Node.js execution. No containers, no VMs — just +npm-compatible sandboxing out of the box. diff --git a/website/src/content/docs/docs/nodejs-compatibility.mdx b/website/src/content/docs/docs/nodejs-compatibility.mdx index 78786823a..f159c9423 100644 --- a/website/src/content/docs/docs/nodejs-compatibility.mdx +++ b/website/src/content/docs/docs/nodejs-compatibility.mdx @@ -2,7 +2,6 @@ title: Node.js Compatibility description: Which node builtins guest code can import in Secure Exec, and how each one is backed. --- -import { Aside } from '@astrojs/starlight/components'; Guest code in Secure Exec runs as Node.js. It never touches the host runtime: every guest `import`/`require` of a `node:` builtin resolves to a kernel-backed bridge or an in-isolate polyfill, never the real host module. This page describes which builtins are available and how each one is implemented. @@ -18,7 +17,7 @@ There are three ways a builtin is provided to guest code: The canonical inventory lives in `crates/execution/assets/polyfill-registry.json`. - +A guest never falls through to a real host builtin. Anything not bridged or polyfilled is denied, so there is no path where guest code reaches the host runtime. ## Bridge-backed builtins @@ -86,7 +85,7 @@ WebAssembly is enabled inside the isolate (`WebAssembly.Module`, `WebAssembly.In The builtin surface can be narrowed through the [platform / `allowedBuiltins` config](/docs/features/runtime-platform); anything excluded becomes a denied builtin (`ERR_ACCESS_DENIED`). - +This config (`CreateVmConfig.jsRuntime`) rides the wire `CreateVmConfig` and is not currently exposed through `NodeRuntime.create()`. See [Runtime Platform](/docs/features/runtime-platform) for the platform ladder and [TypeScript SDK](/docs/sdks/typescript) for the config shape. ## Logging behavior diff --git a/website/src/content/docs/docs/quickstart.mdx b/website/src/content/docs/docs/quickstart.mdx index 870965784..250fdf188 100644 --- a/website/src/content/docs/docs/quickstart.mdx +++ b/website/src/content/docs/docs/quickstart.mdx @@ -3,33 +3,27 @@ title: Quickstart description: Get Secure Exec running in a few minutes. --- -import { Tabs, TabItem, Steps, CardGrid, LinkCard } from '@astrojs/starlight/components'; - + 1. **Install** - - - ```bash - npm install secure-exec - ``` - - - ```bash - bun add secure-exec - ``` - - - ```bash - pnpm add secure-exec - ``` - - - ```bash - yarn add secure-exec - ``` - - + + ```bash title="npm" + npm install secure-exec + ``` + + ```bash title="bun" + bun add secure-exec + ``` + + ```bash title="pnpm" + pnpm add secure-exec + ``` + + ```bash title="yarn" + yarn add secure-exec + ``` + 2. **Create a runtime** @@ -45,55 +39,29 @@ import { Tabs, TabItem, Steps, CardGrid, LinkCard } from '@astrojs/starlight/com Use `run()` when you want a JSON value back; the guest calls `globalThis.__return(value)` to set it. Use `exec()` when you care about side effects and want to capture `stdout`/`stderr`/`exitCode`. Guest code runs as an ES module, so `import` and top-level `await` both work. - - - ```ts - import { NodeRuntime } from "secure-exec"; - - // Boot a fully virtualized runtime. Guest code runs inside the kernel - // isolation boundary - no host escapes. - const runtime = await NodeRuntime.create(); - - try { - // run() executes guest JavaScript as an ES module and returns the value the - // guest passes to globalThis.__return(). stdout/stderr are captured too. - const result = await runtime.run<{ message: string; sum: number }>(` - console.log("hello from secure-exec"); - __return({ message: "hello from secure-exec", sum: 1 + 2 }); - `); - - console.log("stdout:", JSON.stringify(result.stdout.trim())); - console.log("value:", result.value); - console.log("exitCode:", result.exitCode); - } finally { - // Tear down the VM and release the sidecar. - await runtime.dispose(); - } - ``` - - - - ```ts - import { NodeRuntime } from "secure-exec"; - - const runtime = await NodeRuntime.create(); - - try { - // exec() runs guest code for its side effects and captures the streams. - const result = await runtime.exec(` - console.log("hello from secure-exec"); - console.error("this goes to stderr"); - `); - - console.log("stdout:", JSON.stringify(result.stdout.trim())); - console.log("stderr:", JSON.stringify(result.stderr.trim())); - console.log("exitCode:", result.exitCode); - } finally { - await runtime.dispose(); - } - ``` - - + + + + ```ts title="Capture output" + import { NodeRuntime } from "secure-exec"; + + const runtime = await NodeRuntime.create(); + + try { + // exec() runs guest code for its side effects and captures the streams. + const result = await runtime.exec(` + console.log("hello from secure-exec"); + console.error("this goes to stderr"); + `); + + console.log("stdout:", JSON.stringify(result.stdout.trim())); + console.log("stderr:", JSON.stringify(result.stderr.trim())); + console.log("exitCode:", result.exitCode); + } finally { + await runtime.dispose(); + } + ``` + *[See Full Example](https://github.com/rivet-dev/secure-exec/tree/main/examples/docs/quickstart)* @@ -108,11 +76,16 @@ import { Tabs, TabItem, Steps, CardGrid, LinkCard } from '@astrojs/starlight/com ``` See [Permissions](/docs/features/permissions) for the full scope list and merge semantics. + ## Next steps - - - - + + + A fast tour of the essential SDK API and core concepts. + + + Control filesystem, network, and process access. + + diff --git a/website/src/content/docs/docs/sdks/rust.mdx b/website/src/content/docs/docs/sdks/rust.mdx index 48d22ff54..5c1fb09f9 100644 --- a/website/src/content/docs/docs/sdks/rust.mdx +++ b/website/src/content/docs/docs/sdks/rust.mdx @@ -2,7 +2,6 @@ title: Rust SDK description: Install the Secure Exec Rust client and find its generated docs.rs reference. --- -import { LinkCard } from '@astrojs/starlight/components'; The `secure-exec-client` crate is the Rust SDK. It speaks the same sidecar wire protocol as the TypeScript client, so every capability reachable from `secure-exec` is also reachable from Rust through `SidecarProcess`. @@ -23,8 +22,6 @@ secure-exec-client = "*" The full reference is generated with rustdoc and published to docs.rs. Use it as the source of truth for signatures and types. - + + Generated rustdoc for the Rust client crate. + diff --git a/website/src/content/docs/docs/sdks/typescript.mdx b/website/src/content/docs/docs/sdks/typescript.mdx index fe4f90bf6..336ab4ec4 100644 --- a/website/src/content/docs/docs/sdks/typescript.mdx +++ b/website/src/content/docs/docs/sdks/typescript.mdx @@ -2,7 +2,6 @@ title: TypeScript SDK description: Install the Secure Exec TypeScript SDK and find its generated API reference. --- -import { LinkCard } from '@astrojs/starlight/components'; The `secure-exec` package is the TypeScript SDK. It exports `NodeRuntime`, the batteries-included entry point for booting a virtualized VM and running guest JavaScript, plus the types describing its options and results. @@ -28,8 +27,6 @@ try { The full type-level reference is generated from the source with TypeDoc and is the source of truth for every export, method, and option. - + + Generated TSDoc for the secure-exec package. + diff --git a/website/src/content/docs/docs/security-model.mdx b/website/src/content/docs/docs/security-model.mdx index cc87ffa55..6d22d5d4f 100644 --- a/website/src/content/docs/docs/security-model.mdx +++ b/website/src/content/docs/docs/security-model.mdx @@ -2,7 +2,6 @@ title: Security Model description: A short overview of Secure Exec isolation and trust, with a link to the canonical agentOS security model. --- -import { LinkCard } from '@astrojs/starlight/components'; Secure Exec runs guest code inside a fully virtualized VM so untrusted code stays contained. At a glance: @@ -15,8 +14,6 @@ Secure Exec runs guest code inside a fully virtualized VM so untrusted code stay The canonical threat model, trust boundaries, and detailed enforcement guarantees are owned by agentOS. - + + The complete trust model, threat model, and enforcement details. + diff --git a/website/src/content/docs/docs/use-cases/ai-agent-code-exec.mdx b/website/src/content/docs/docs/use-cases/ai-agent-code-exec.mdx index 2e2476b2f..d39711837 100644 --- a/website/src/content/docs/docs/use-cases/ai-agent-code-exec.mdx +++ b/website/src/content/docs/docs/use-cases/ai-agent-code-exec.mdx @@ -3,9 +3,9 @@ title: AI Agent Code Exec description: Give AI agents a secure code-execution tool that runs untrusted code in a sandbox and returns structured results. --- -import { LinkCard } from '@astrojs/starlight/components'; - - + + Full working example that runs untrusted code and captures its result. + Give your agent a code-execution tool that runs untrusted, model-generated code in a fully virtualized VM. The agent writes code, it runs inside the kernel isolation boundary with no access to the host, and you get back its stdout and a structured return value. @@ -15,46 +15,7 @@ Give your agent a code-execution tool that runs untrusted, model-generated code The guest code runs as a standard ES module (top-level `await` and `import` work), but it can only see the virtual filesystem and kernel-mediated syscalls, and it cannot reach the host machine. -```ts AI Agent Code Exec -import { NodeRuntime } from "secure-exec"; - -// Imagine this string came from an AI agent. We never trust it: it runs fully -// sandboxed inside the secure-exec VM, with no access to the host machine. -const untrustedCode = ` -const fib = [0, 1]; -while (fib.length < 20) { - fib.push(fib[fib.length - 1] + fib[fib.length - 2]); -} -console.log("computed", fib.length, "fibonacci numbers"); -// Hand a JSON-serializable value back to the host. -globalThis.__return({ fibonacci: fib, sum: fib.reduce((a, b) => a + b, 0) }); -`; - -const rt = await NodeRuntime.create(); -try { - // rt.run() executes the guest code and decodes whatever it passes to - // globalThis.__return(), while still capturing stdout/stderr/exitCode. - const result = await rt.run<{ fibonacci: number[]; sum: number }>( - untrustedCode, - { timeout: 5000 }, - ); - - console.log("exitCode:", result.exitCode); - console.log("stdout:", result.stdout.trim()); - console.log("returned value:", JSON.stringify(result.value)); - - // The sandbox presents normal Node semantics, but the code cannot touch the - // host: it only ever sees the virtual filesystem and kernel-mediated syscalls. - const escapeAttempt = await rt.exec( - `import os from "node:os";\nconsole.log("guest hostname:", os.hostname());`, - { timeout: 5000 }, - ); - console.log("\nescape attempt exitCode:", escapeAttempt.exitCode); - console.log("escape attempt stdout:", escapeAttempt.stdout.trim()); -} finally { - await rt.dispose(); -} -``` + *[See Full Example](https://github.com/rivet-dev/secure-exec/tree/main/examples/docs/uc-ai-agent-code-exec)* @@ -87,6 +48,8 @@ const rt = await NodeRuntime.create({ }); ``` - + + The full policy model: scopes, rule sets, and how partial policies merge over the secure default. + You can also constrain the run with `env` and `cwd` on `NodeRuntime.create()`, and `env`, `cwd`, `stdin`, and `timeout` on each `run()` / `exec()` call. diff --git a/website/src/content/docs/docs/use-cases/code-mode.mdx b/website/src/content/docs/docs/use-cases/code-mode.mdx index 83cbcc96d..602832ac9 100644 --- a/website/src/content/docs/docs/use-cases/code-mode.mdx +++ b/website/src/content/docs/docs/use-cases/code-mode.mdx @@ -3,15 +3,15 @@ title: "Code Mode (MCP)" description: "Give AI agents a single code-execution tool instead of individual MCP tools. The LLM writes code that chains binding calls, executed safely in Secure Exec." --- -import { Aside, LinkCard } from '@astrojs/starlight/components'; - - + + Full working example: the LLM chains real host binding calls in one sandboxed run and returns a structured result. + Instead of calling MCP tools one at a time, Code Mode lets the LLM write JavaScript that orchestrates everything in one go, run safely in a V8 sandbox by Secure Exec. - + ## Why Code Mode @@ -33,106 +33,19 @@ Host bindings are the heart of Code Mode. The handlers run on the host, never in Each binding has a `description`, a JSON Schema `inputSchema`, and a `handler`. The handler receives the parsed input and returns a JSON-serializable result. -```ts -import { NodeRuntime } from "secure-exec"; - -function readStringField(input: unknown, field: string): string { - if (!input || typeof input !== "object" || Array.isArray(input)) { - throw new TypeError("binding input must be an object"); - } - - const value = (input as Record)[field]; - if (typeof value !== "string") { - throw new TypeError(`${field} must be a string`); - } - return value; -} - -// Register the host bindings. These handlers run on the HOST, not in the sandbox. -// In a real app each handler would hit a database, an API, or a service; here we -// keep them small and deterministic so the example is easy to follow. -const rt = await NodeRuntime.create({ - bindings: { - "get-weather": { - description: "Look up the current temperature for a city", - inputSchema: { - type: "object", - properties: { city: { type: "string" } }, - required: ["city"], - }, - handler: (input) => { - const city = readStringField(input, "city"); - const table: Record = { - "San Francisco": { temp_f: 61 }, - Tokyo: { temp_f: 75 }, - }; - return table[city] ?? { temp_f: null }; - }, - }, - calculate: { - description: "Evaluate a simple arithmetic expression", - inputSchema: { - type: "object", - properties: { expression: { type: "string" } }, - required: ["expression"], - }, - handler: (input) => { - const expression = readStringField(input, "expression"); - return { result: Number(eval(expression)) }; - }, - }, - }, -}); -``` + ## The agent's generated code The agent then generates code like this (call it `llmGeneratedCode`). The guest calls each binding with the `callBinding(name, input)` global, which resolves with the host handler's return value. It chains three binding calls with real control flow (`Promise.all`, arithmetic, branching) in one execution, then returns a single structured result: -```ts -// Imagine this string was written by the LLM. It chains three host binding calls -// with real control flow (Promise.all, arithmetic, branching) in one execution, -// then hands a single structured result back to the host. callBinding resolves -// with the host handler's return value. -const llmGeneratedCode = ` -const [sf, tokyo] = await Promise.all([ - callBinding("get-weather", { city: "San Francisco" }), - callBinding("get-weather", { city: "Tokyo" }), -]); - -const diffF = Math.abs(sf.temp_f - tokyo.temp_f); -const diffC = await callBinding("calculate", { expression: \`\${diffF} * 5 / 9\` }); - -console.log("chained 3 binding calls in one sandbox execution"); - -globalThis.__return({ - san_francisco: sf, - tokyo: tokyo, - difference: { fahrenheit: diffF, celsius: diffC.result }, - warmer: sf.temp_f > tokyo.temp_f ? "San Francisco" : "Tokyo", -}); -`; -``` + ## Run it and read the result Run the LLM's code in one sandboxed pass and read back the structured result: -```ts -try { - // rt.run() executes the guest code and decodes whatever it passes to - // globalThis.__return(), while still capturing stdout/stderr/exitCode. - const result = await rt.run(llmGeneratedCode, { timeout: 5000 }); - - console.log("exitCode:", result.exitCode); - console.log("stdout:", result.stdout.trim()); - console.log("structured result:", JSON.stringify(result.value, null, 2)); -} finally { - await rt.dispose(); -} -``` - -*[See Full Example](https://github.com/rivet-dev/secure-exec/tree/main/examples/docs/uc-code-mode)* + Three tool calls, one sandbox execution, zero extra LLM round-trips. Running it prints: diff --git a/website/src/content/docs/docs/use-cases/dev-servers.mdx b/website/src/content/docs/docs/use-cases/dev-servers.mdx index e7f2941ad..cb7b966fa 100644 --- a/website/src/content/docs/docs/use-cases/dev-servers.mdx +++ b/website/src/content/docs/docs/use-cases/dev-servers.mdx @@ -3,9 +3,9 @@ title: Dev Servers description: Run user-provided server-style code (HTTP servers, request handlers) inside a secure isolate. --- -import { LinkCard } from '@astrojs/starlight/components'; - - + + Full working example that boots a long-running HTTP server inside a sandboxed isolate and drives host requests into it. + Let users run their own server-style code inside a sandboxed isolate. A guest program can boot a real `node:http` server, bind a loopback port owned by the kernel, and serve requests, all without touching the host machine. diff --git a/website/src/content/docs/docs/use-cases/plugin-systems.mdx b/website/src/content/docs/docs/use-cases/plugin-systems.mdx index 38f59275f..fbe026848 100644 --- a/website/src/content/docs/docs/use-cases/plugin-systems.mdx +++ b/website/src/content/docs/docs/use-cases/plugin-systems.mdx @@ -11,78 +11,7 @@ The host owns the plugin source and the input. Run the plugin with `run()` insid The plugin below gets filesystem access but no network access. The guest proves it cannot reach the network, then transforms the host-supplied input. -```ts Plugin Runner -import { NodeRuntime } from "secure-exec"; - -// Boot a sandboxed VM for running untrusted plugin code. The plugin can use -// the filesystem, but network access is denied. (childProcess/process stay -// allowed because the kernel spawns the guest `node` process to run the -// plugin - denying it would block the runtime itself.) -const runtime = await NodeRuntime.create({ - permissions: { - fs: "allow", - network: "deny", - childProcess: "allow", - process: "allow", - env: "allow", - }, -}); - -try { - // The host owns the plugin source and the input. Here the plugin is a - // title-case transformer; in a real system it would be uploaded by a user. - const pluginSource = ` - function transform(input, options = {}) { - const words = String(input) - .split(/\\s+/) - .filter(Boolean) - .map((w) => w.charAt(0).toUpperCase() + w.slice(1).toLowerCase()); - return (options.prefix ?? "") + words.join(" "); - } - const manifest = { name: "title-case", version: "1.0.0" }; - `; - - const input = "hello from plugin land"; - const options = { prefix: "Plugin says: " }; - - // Run the plugin in isolation and get a structured value back via run(). - // The guest calls __return() with a JSON-serializable value, decoded on the - // host as result.value. The plugin also proves it cannot reach the network. - const { value, stdout, exitCode } = await runtime.run<{ - manifest: { name: string; version: string }; - output: string; - networkBlocked: boolean; - }>(` - ${pluginSource} - - console.log("running plugin:", manifest.name); - - let networkBlocked = false; - try { - await fetch("http://example.com"); - } catch { - networkBlocked = true; - } - - __return({ - manifest, - output: transform(${JSON.stringify(input)}, ${JSON.stringify(options)}), - networkBlocked, - }); - `); - - console.log("guest stdout:", stdout.trim()); - console.log("exit code:", exitCode); - console.log("plugin name:", value?.manifest.name); - console.log("plugin version:", value?.manifest.version); - console.log("plugin output:", value?.output); - console.log("network blocked:", value?.networkBlocked); -} finally { - await runtime.dispose(); -} -``` - -*[See Full Example](https://github.com/rivet-dev/secure-exec/tree/main/examples/docs/uc-plugin-systems)* + The plugin executes inside the kernel isolation boundary with only the capabilities you granted (network access is denied here), and the host gets back structured data via `__return()` rather than direct access to plugin internals. @@ -132,8 +61,6 @@ try { } ``` -*[See Full Example](https://github.com/rivet-dev/secure-exec/tree/main/examples/docs/uc-code-mode)* - This is safe because the plugin reaches host capability only through the curated tool surface, never the underlying access behind it. The `tool` permission scope gates invocation: when you pass `tools` and set no `tool` policy, the scope is granted so the registered tools are invocable, but you can supply your own `permissions.tool` policy to gate individual tools. See [Bindings](/docs/features/bindings) for the full guide, including input schemas, command aliases, and worked examples. diff --git a/website/src/data/docs-landings.ts b/website/src/data/docs-landings.ts new file mode 100644 index 000000000..3937164d9 --- /dev/null +++ b/website/src/data/docs-landings.ts @@ -0,0 +1,32 @@ +import { + faRocket, + faTerminal, + faLayerGroup, +} from "@rivet-gg/icons"; +import type { DocsLandingData } from "@rivet-dev/docs-theme/components/docs/DocsLanding"; + +/** + * Section-overview landings (the icon-grid element, like rivet.dev's docs + * landings). Keyed by route; [...slug].astro renders for a + * matching path instead of the prose article. + * + * Built from secure-exec's `siteConfig.landing` ({ title, subtitle, cards }), + * mapping each card's icon string onto a FontAwesome IconDefinition. + */ +export const docsLandings: Record = { + "/docs": { + title: "Documentation", + subtitle: + "A lightweight library for secure Node.js execution. No containers, no VMs — just npm-compatible sandboxing out of the box.", + sections: [ + { + title: "Get Started", + items: [ + { title: "Quickstart", href: "/docs/quickstart", icon: faRocket, description: "Install and run your first sandboxed execution in a few minutes." }, + { title: "Crash Course", href: "/docs/crash-course", icon: faTerminal, description: "A fast tour of the secure-exec SDK: run code, capture output, and the core concepts." }, + { title: "Executing Code", href: "/docs/features/executing-code", icon: faLayerGroup, description: "Run code and TypeScript, capture output, and load npm modules in the sandbox." }, + ], + }, + ], + }, +}; diff --git a/website/src/generated/routes.json b/website/src/generated/routes.json new file mode 100644 index 000000000..2ab2f0e65 --- /dev/null +++ b/website/src/generated/routes.json @@ -0,0 +1,120 @@ +{ + "pages": { + "/docs/docs/architecture": { + "title": "Architecture", + "description": "A short overview of the Secure Exec architecture, with a link to the canonical agentOS architecture docs." + }, + "/docs/docs/benchmarks": { + "title": "Benchmarks", + "description": "Cold start, warm execution, and reuse fast-path measurements for the Secure Exec SDK." + }, + "/docs/docs/crash-course": { + "title": "Crash Course", + "description": "A fast tour of Secure Exec: install, run code, capture output, and the core SDK concepts." + }, + "/docs/docs": { + "title": "Introduction", + "description": "'Secure Exec: a fully virtualized runtime for executing untrusted code with zero host escapes.'" + }, + "/docs/docs/nodejs-compatibility": { + "title": "Node.js Compatibility", + "description": "Which node builtins guest code can import in Secure Exec, and how each one is backed." + }, + "/docs/docs/quickstart": { + "title": "Quickstart", + "description": "Get Secure Exec running in a few minutes." + }, + "/docs/docs/security-model": { + "title": "Security Model", + "description": "A short overview of Secure Exec isolation and trust, with a link to the canonical agentOS security model." + }, + "/docs/docs/comparison/cloudflare-workers": { + "title": "Secure Exec vs Cloudflare Workers", + "description": "How Secure Exec and Cloudflare Workers differ in isolation model, permissions, networking, and Node.js compatibility." + }, + "/docs/docs/comparison/isolated-vm": { + "title": "Secure Exec vs isolated-vm", + "description": "How Secure Exec and isolated-vm differ in isolation surface, security confinement, performance, and developer experience." + }, + "/docs/docs/comparison/quickjs": { + "title": "Secure Exec vs QuickJS", + "description": "How Secure Exec and QuickJS differ in isolation model, performance, language coverage, and system surface." + }, + "/docs/docs/comparison/sandbox": { + "title": "Secure Exec vs Container Sandbox", + "description": "When to use a container sandbox versus Secure Exec for running untrusted code." + }, + "/docs/docs/features/bindings": { + "title": "Bindings", + "description": "Give sandboxed guest code a narrow, curated set of host-backed capabilities." + }, + "/docs/docs/features/child-processes": { + "title": "Child Processes", + "description": "Spawn child processes from sandboxed code." + }, + "/docs/docs/features/executing-code": { + "title": "Executing Code", + "description": "Run guest JavaScript with exec() and run(), and return values from the sandbox." + }, + "/docs/docs/features/filesystem": { + "title": "Filesystem", + "description": "A short overview of the Secure Exec filesystem, with a link to the canonical agentOS filesystem docs." + }, + "/docs/docs/features/module-loading": { + "title": "NPM & Module Loading", + "description": "How sandboxed code resolves and loads modules." + }, + "/docs/docs/features/networking": { + "title": "Networking", + "description": "A short overview of Secure Exec networking, with a link to the canonical agentOS networking docs." + }, + "/docs/docs/features/output-capture": { + "title": "Output Capture", + "description": "Capture console output from sandboxed code." + }, + "/docs/docs/features/permissions": { + "title": "Permissions", + "description": "A short overview of Secure Exec permissions, with a link to the canonical agentOS permissions docs." + }, + "/docs/docs/features/resident-runner": { + "title": "Resident Runner", + "description": "Reuse a live guest process for low-latency repeated execution." + }, + "/docs/docs/features/resource-limits": { + "title": "Resource Limits", + "description": "Secure Exec resource limits, defaults, backpressure constants, and warning names." + }, + "/docs/docs/features/runtime-platform": { + "title": "Runtime & Platform", + "description": "Customize the host environment guest code sees (the full Node.js surface today), plus the platform ladder (node, browser, neutral, bare) the kernel models." + }, + "/docs/docs/features/typescript": { + "title": "TypeScript", + "description": "Compiling and type-checking TypeScript inside the sandbox." + }, + "/docs/docs/sdks/rust": { + "title": "Rust SDK", + "description": "Install the Secure Exec Rust client and find its generated docs.rs reference." + }, + "/docs/docs/sdks/typescript": { + "title": "TypeScript SDK", + "description": "Install the Secure Exec TypeScript SDK and find its generated API reference." + }, + "/docs/docs/use-cases/ai-agent-code-exec": { + "title": "AI Agent Code Exec", + "description": "Give AI agents a secure code-execution tool that runs untrusted code in a sandbox and returns structured results." + }, + "/docs/docs/use-cases/code-mode": { + "title": "Code Mode (MCP)", + "description": "Give AI agents a single code-execution tool instead of individual MCP tools. The LLM writes code that chains binding calls, executed safely in Secure Exec." + }, + "/docs/docs/use-cases/dev-servers": { + "title": "Dev Servers", + "description": "Run user-provided server-style code (HTTP servers, request handlers) inside a secure isolate." + }, + "/docs/docs/use-cases/plugin-systems": { + "title": "Plugin Systems", + "description": "Run user-authored plugins in isolation with explicit permissions." + } + } +} \ No newline at end of file diff --git a/website/src/lib/starlight-shim.jsx b/website/src/lib/starlight-shim.jsx new file mode 100644 index 000000000..c9ed2072a --- /dev/null +++ b/website/src/lib/starlight-shim.jsx @@ -0,0 +1,58 @@ +/** + * Compatibility shim for `@astrojs/starlight/components`. + * + * The secure-exec docs CONTENT (src/content/docs/**) was authored against + * Starlight and still imports `Aside`, `LinkCard`, `Tabs`, `TabItem`, `Steps`, + * and `CardGrid` from `@astrojs/starlight/components`. The de-Starlighted + * @rivet-dev/docs-theme ships equivalent MDX primitives under different names + * and prop shapes. astro.config.mjs aliases the Starlight import path to this + * file so the existing content builds unchanged. + * + * NOTE: this is the build FOUNDATION. Phase 2 rewrites the doc content to import + * the theme's components directly; once that lands, this shim and its alias can + * be removed. + */ +import { + Tabs as ThemeTabs, + Tab as ThemeTab, + Steps as ThemeSteps, + Card as ThemeCard, + CardGroup as ThemeCardGroup, + Note, + Tip, + Warning, +} from "@rivet-dev/docs-theme/components/mdx.jsx"; + +export const Tabs = ThemeTabs; + +// Starlight's -> theme's +export const TabItem = ({ label, title, ...props }) => ( + +); + +export const Steps = ThemeSteps; + +// Starlight's -> theme's +export const CardGrid = ThemeCardGroup; + +// Starlight's -> theme's +export const LinkCard = ({ title, href, description, target, ...props }) => ( + + {description} + +); + +// Starlight's -> theme's +export const Card = ThemeCard; + +// Starlight's +// -> theme callouts (Note / Tip / Warning). +export const Aside = ({ type = "note", title, children }) => { + const Variant = type === "tip" ? Tip : type === "caution" || type === "danger" ? Warning : Note; + return ( + + {title ? {title} : null} + {children} + + ); +}; diff --git a/website/src/pages/[...slug].astro b/website/src/pages/[...slug].astro new file mode 100644 index 000000000..e848b1866 --- /dev/null +++ b/website/src/pages/[...slug].astro @@ -0,0 +1,101 @@ +--- +import { getCollection, render } from "astro:content"; +import DocsLayout from "@rivet-dev/docs-theme/layouts/DocsLayout.astro"; +import { DocsNavigation } from "@rivet-dev/docs-theme/components/DocsNavigation"; +import { DocsTableOfContents } from "@rivet-dev/docs-theme/components/DocsTableOfContents"; +import { DocsPageDropdown } from "@rivet-dev/docs-theme/components/DocsPageDropdown"; +import { Prose } from "@rivet-dev/docs-theme/components/Prose.jsx"; +import { findActiveTab } from "@rivet-dev/docs-theme/sitemap"; +import { Icon, faPencil } from "@rivet-gg/icons"; +import * as mdxComponents from "@rivet-dev/docs-theme/components/mdx.jsx"; +import { DocsLanding } from "@rivet-dev/docs-theme/components/docs/DocsLanding"; +import { Footer } from "../components/Footer"; +import { docsLandings } from "../data/docs-landings"; +import config from "virtual:rivet-docs/config"; + +export async function getStaticPaths() { + const docs = await getCollection("docs"); + return docs.map((entry) => ({ + params: { slug: entry.id }, + props: { entry }, + })); +} + +const { entry } = Astro.props; +const { Content, headings } = await render(entry); + +const { title, description } = entry.data as { title: string; description?: string }; + +const fullPath = `/${entry.id}/`.replace(/\/+$/, "/"); +const foundTab = findActiveTab(fullPath, config.sitemap ?? []); +const sidebar = foundTab?.tab?.sidebar ?? []; +const parentPage = (foundTab as any)?.page?.parent; + +const markdownPath = entry.id; +const componentSourcePath = `docs/${entry.id}.mdx`; + +// Section-overview landing (icon grid) for /docs. +const landing = docsLandings[`/${entry.id}`] ?? null; + +// Build table of contents from h2/h3 headings (rivet shape). +const tableOfContents = headings + .filter((h) => h.depth === 2 || h.depth === 3) + .reduce((acc, h) => { + if (h.depth === 2) { + acc.push({ title: h.text, id: h.slug, children: [] }); + } else if (acc.length > 0) { + acc[acc.length - 1].children.push({ title: h.text, id: h.slug, children: [] }); + } + return acc; + }, [] as Array<{ title: string; id: string; children: Array<{ title: string; id: string; children: never[] }> }>); +--- + + + + +