diff --git a/eslint.config.js b/eslint.config.js
index 77566a65..eab69c34 100644
--- a/eslint.config.js
+++ b/eslint.config.js
@@ -271,10 +271,7 @@ export default [
},
},
{
- files: [
- "backend/**/*.{js,jsx,ts,tsx}",
- "iframe-outputs/**/*.{js,jsx,ts,tsx}",
- ],
+ files: ["backend/**/*.{js,jsx,ts,tsx}", "packages/**/*.{js,jsx,ts,tsx}"],
languageOptions: {
parser: tsparser,
ecmaVersion: 2022,
@@ -324,8 +321,8 @@ export default [
"node_modules/**",
"*.d.ts",
"scripts/**",
- "iframe-outputs/worker/dist/**",
- "iframe-outputs/worker/.wrangler/**",
+ "packages/iframe-outputs/worker/dist/**",
+ "packages/iframe-outputs/worker/.wrangler/**",
],
},
];
diff --git a/iframe-outputs/src/tsconfig.node.json b/iframe-outputs/src/tsconfig.node.json
deleted file mode 100644
index 42872c59..00000000
--- a/iframe-outputs/src/tsconfig.node.json
+++ /dev/null
@@ -1,10 +0,0 @@
-{
- "compilerOptions": {
- "composite": true,
- "skipLibCheck": true,
- "module": "ESNext",
- "moduleResolution": "bundler",
- "allowSyntheticDefaultImports": true
- },
- "include": ["vite.config.ts"]
-}
diff --git a/iframe-outputs/worker/package.json b/iframe-outputs/worker/package.json
deleted file mode 100644
index 1e1e2858..00000000
--- a/iframe-outputs/worker/package.json
+++ /dev/null
@@ -1,33 +0,0 @@
-{
- "name": "anode-iframe-outputs",
- "version": "0.2.0",
- "private": true,
- "description": "Isolated iframe content server for Anode user-generated outputs",
- "type": "module",
- "engines": {
- "node": ">=23.0.0",
- "pnpm": ">=10.9.0"
- },
- "scripts": {
- "deploy": "wrangler deploy --env production",
- "deploy:production": "wrangler deploy --env production",
- "deploy:preview": "wrangler deploy --env preview",
- "deploy:preview-dry-run": "wrangler deploy --env preview --dry-run",
- "deploy:production-dry-run": "wrangler deploy --env production --dry-run",
- "logs": "wrangler tail --env production",
- "logs:preview": "wrangler tail --env preview"
- },
- "devDependencies": {
- "@cloudflare/workers-types": "^4.20250106.0",
- "typescript": "^5.8.3",
- "wrangler": "4.25.0"
- },
- "keywords": [
- "iframe",
- "sandbox",
- "user-content",
- "cloudflare-worker"
- ],
- "author": "Runt Team",
- "license": "MIT"
-}
diff --git a/iframe-outputs/worker/pnpm-lock.yaml b/iframe-outputs/worker/pnpm-lock.yaml
deleted file mode 100644
index b77c4924..00000000
--- a/iframe-outputs/worker/pnpm-lock.yaml
+++ /dev/null
@@ -1,920 +0,0 @@
-lockfileVersion: '9.0'
-
-settings:
- autoInstallPeers: true
- excludeLinksFromLockfile: false
-
-importers:
-
- .:
- devDependencies:
- '@cloudflare/workers-types':
- specifier: ^4.20250106.0
- version: 4.20250730.0
- typescript:
- specifier: ^5.8.3
- version: 5.8.3
- wrangler:
- specifier: 4.25.0
- version: 4.25.0(@cloudflare/workers-types@4.20250730.0)
-
-packages:
-
- '@cloudflare/kv-asset-handler@0.4.0':
- resolution: {integrity: sha512-+tv3z+SPp+gqTIcImN9o0hqE9xyfQjI1XD9pL6NuKjua9B1y7mNYv0S9cP+QEbA4ppVgGZEmKOvHX5G5Ei1CVA==}
- engines: {node: '>=18.0.0'}
-
- '@cloudflare/unenv-preset@2.3.3':
- resolution: {integrity: sha512-/M3MEcj3V2WHIRSW1eAQBPRJ6JnGQHc6JKMAPLkDb7pLs3m6X9ES/+K3ceGqxI6TKeF32AWAi7ls0AYzVxCP0A==}
- peerDependencies:
- unenv: 2.0.0-rc.17
- workerd: ^1.20250508.0
- peerDependenciesMeta:
- workerd:
- optional: true
-
- '@cloudflare/workerd-darwin-64@1.20250712.0':
- resolution: {integrity: sha512-M6S6a/LQ0Jb0R+g0XhlYi1adGifvYmxA5mD/i9TuZZgjs2bIm5ELuka/n3SCnI98ltvlx3HahRaHagAtOilsFg==}
- engines: {node: '>=16'}
- cpu: [x64]
- os: [darwin]
-
- '@cloudflare/workerd-darwin-arm64@1.20250712.0':
- resolution: {integrity: sha512-7sFzn6rvAcnLy7MktFL42dYtzL0Idw/kiUmNf2P3TvsBRoShhLK5ZKhbw+NAhvU8e4pXWm5lkE0XmpieA0zNjw==}
- engines: {node: '>=16'}
- cpu: [arm64]
- os: [darwin]
-
- '@cloudflare/workerd-linux-64@1.20250712.0':
- resolution: {integrity: sha512-EFRrGe/bqK7NHtht7vNlbrDpfvH3eRvtJOgsTpEQEysDjVmlK6pVJxSnLy9Hg1zlLY15IfhfGC+K2qisseHGJQ==}
- engines: {node: '>=16'}
- cpu: [x64]
- os: [linux]
-
- '@cloudflare/workerd-linux-arm64@1.20250712.0':
- resolution: {integrity: sha512-rG8JUleddhUHQVwpXOYv0VbL0S9kOtR9PNKecgVhFpxEhC8aTeg2HNBBjo8st7IfcUvY8WaW3pD3qdAMZ05UwQ==}
- engines: {node: '>=16'}
- cpu: [arm64]
- os: [linux]
-
- '@cloudflare/workerd-windows-64@1.20250712.0':
- resolution: {integrity: sha512-qS8H5RCYwE21Om9wo5/F807ClBJIfknhuLBj16eYxvJcj9JqgAKWi12BGgjyGxHuJJjeoQ63lr4wHAdbFntDDg==}
- engines: {node: '>=16'}
- cpu: [x64]
- os: [win32]
-
- '@cloudflare/workers-types@4.20250730.0':
- resolution: {integrity: sha512-hn0KhTnHxmkpNiHn6IGo9ffOqYqmJvrMApE2OT1b+2rp1AYCvFxMf7Xzgfb+1liylmpeyHQjKODhfXrxxIPXsg==}
-
- '@cspotcode/source-map-support@0.8.1':
- resolution: {integrity: sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==}
- engines: {node: '>=12'}
-
- '@emnapi/runtime@1.4.5':
- resolution: {integrity: sha512-++LApOtY0pEEz1zrd9vy1/zXVaVJJ/EbAF3u0fXIzPJEDtnITsBGbbK0EkM72amhl/R5b+5xx0Y/QhcVOpuulg==}
-
- '@esbuild/aix-ppc64@0.25.4':
- resolution: {integrity: sha512-1VCICWypeQKhVbE9oW/sJaAmjLxhVqacdkvPLEjwlttjfwENRSClS8EjBz0KzRyFSCPDIkuXW34Je/vk7zdB7Q==}
- engines: {node: '>=18'}
- cpu: [ppc64]
- os: [aix]
-
- '@esbuild/android-arm64@0.25.4':
- resolution: {integrity: sha512-bBy69pgfhMGtCnwpC/x5QhfxAz/cBgQ9enbtwjf6V9lnPI/hMyT9iWpR1arm0l3kttTr4L0KSLpKmLp/ilKS9A==}
- engines: {node: '>=18'}
- cpu: [arm64]
- os: [android]
-
- '@esbuild/android-arm@0.25.4':
- resolution: {integrity: sha512-QNdQEps7DfFwE3hXiU4BZeOV68HHzYwGd0Nthhd3uCkkEKK7/R6MTgM0P7H7FAs5pU/DIWsviMmEGxEoxIZ+ZQ==}
- engines: {node: '>=18'}
- cpu: [arm]
- os: [android]
-
- '@esbuild/android-x64@0.25.4':
- resolution: {integrity: sha512-TVhdVtQIFuVpIIR282btcGC2oGQoSfZfmBdTip2anCaVYcqWlZXGcdcKIUklfX2wj0JklNYgz39OBqh2cqXvcQ==}
- engines: {node: '>=18'}
- cpu: [x64]
- os: [android]
-
- '@esbuild/darwin-arm64@0.25.4':
- resolution: {integrity: sha512-Y1giCfM4nlHDWEfSckMzeWNdQS31BQGs9/rouw6Ub91tkK79aIMTH3q9xHvzH8d0wDru5Ci0kWB8b3up/nl16g==}
- engines: {node: '>=18'}
- cpu: [arm64]
- os: [darwin]
-
- '@esbuild/darwin-x64@0.25.4':
- resolution: {integrity: sha512-CJsry8ZGM5VFVeyUYB3cdKpd/H69PYez4eJh1W/t38vzutdjEjtP7hB6eLKBoOdxcAlCtEYHzQ/PJ/oU9I4u0A==}
- engines: {node: '>=18'}
- cpu: [x64]
- os: [darwin]
-
- '@esbuild/freebsd-arm64@0.25.4':
- resolution: {integrity: sha512-yYq+39NlTRzU2XmoPW4l5Ifpl9fqSk0nAJYM/V/WUGPEFfek1epLHJIkTQM6bBs1swApjO5nWgvr843g6TjxuQ==}
- engines: {node: '>=18'}
- cpu: [arm64]
- os: [freebsd]
-
- '@esbuild/freebsd-x64@0.25.4':
- resolution: {integrity: sha512-0FgvOJ6UUMflsHSPLzdfDnnBBVoCDtBTVyn/MrWloUNvq/5SFmh13l3dvgRPkDihRxb77Y17MbqbCAa2strMQQ==}
- engines: {node: '>=18'}
- cpu: [x64]
- os: [freebsd]
-
- '@esbuild/linux-arm64@0.25.4':
- resolution: {integrity: sha512-+89UsQTfXdmjIvZS6nUnOOLoXnkUTB9hR5QAeLrQdzOSWZvNSAXAtcRDHWtqAUtAmv7ZM1WPOOeSxDzzzMogiQ==}
- engines: {node: '>=18'}
- cpu: [arm64]
- os: [linux]
-
- '@esbuild/linux-arm@0.25.4':
- resolution: {integrity: sha512-kro4c0P85GMfFYqW4TWOpvmF8rFShbWGnrLqlzp4X1TNWjRY3JMYUfDCtOxPKOIY8B0WC8HN51hGP4I4hz4AaQ==}
- engines: {node: '>=18'}
- cpu: [arm]
- os: [linux]
-
- '@esbuild/linux-ia32@0.25.4':
- resolution: {integrity: sha512-yTEjoapy8UP3rv8dB0ip3AfMpRbyhSN3+hY8mo/i4QXFeDxmiYbEKp3ZRjBKcOP862Ua4b1PDfwlvbuwY7hIGQ==}
- engines: {node: '>=18'}
- cpu: [ia32]
- os: [linux]
-
- '@esbuild/linux-loong64@0.25.4':
- resolution: {integrity: sha512-NeqqYkrcGzFwi6CGRGNMOjWGGSYOpqwCjS9fvaUlX5s3zwOtn1qwg1s2iE2svBe4Q/YOG1q6875lcAoQK/F4VA==}
- engines: {node: '>=18'}
- cpu: [loong64]
- os: [linux]
-
- '@esbuild/linux-mips64el@0.25.4':
- resolution: {integrity: sha512-IcvTlF9dtLrfL/M8WgNI/qJYBENP3ekgsHbYUIzEzq5XJzzVEV/fXY9WFPfEEXmu3ck2qJP8LG/p3Q8f7Zc2Xg==}
- engines: {node: '>=18'}
- cpu: [mips64el]
- os: [linux]
-
- '@esbuild/linux-ppc64@0.25.4':
- resolution: {integrity: sha512-HOy0aLTJTVtoTeGZh4HSXaO6M95qu4k5lJcH4gxv56iaycfz1S8GO/5Jh6X4Y1YiI0h7cRyLi+HixMR+88swag==}
- engines: {node: '>=18'}
- cpu: [ppc64]
- os: [linux]
-
- '@esbuild/linux-riscv64@0.25.4':
- resolution: {integrity: sha512-i8JUDAufpz9jOzo4yIShCTcXzS07vEgWzyX3NH2G7LEFVgrLEhjwL3ajFE4fZI3I4ZgiM7JH3GQ7ReObROvSUA==}
- engines: {node: '>=18'}
- cpu: [riscv64]
- os: [linux]
-
- '@esbuild/linux-s390x@0.25.4':
- resolution: {integrity: sha512-jFnu+6UbLlzIjPQpWCNh5QtrcNfMLjgIavnwPQAfoGx4q17ocOU9MsQ2QVvFxwQoWpZT8DvTLooTvmOQXkO51g==}
- engines: {node: '>=18'}
- cpu: [s390x]
- os: [linux]
-
- '@esbuild/linux-x64@0.25.4':
- resolution: {integrity: sha512-6e0cvXwzOnVWJHq+mskP8DNSrKBr1bULBvnFLpc1KY+d+irZSgZ02TGse5FsafKS5jg2e4pbvK6TPXaF/A6+CA==}
- engines: {node: '>=18'}
- cpu: [x64]
- os: [linux]
-
- '@esbuild/netbsd-arm64@0.25.4':
- resolution: {integrity: sha512-vUnkBYxZW4hL/ie91hSqaSNjulOnYXE1VSLusnvHg2u3jewJBz3YzB9+oCw8DABeVqZGg94t9tyZFoHma8gWZQ==}
- engines: {node: '>=18'}
- cpu: [arm64]
- os: [netbsd]
-
- '@esbuild/netbsd-x64@0.25.4':
- resolution: {integrity: sha512-XAg8pIQn5CzhOB8odIcAm42QsOfa98SBeKUdo4xa8OvX8LbMZqEtgeWE9P/Wxt7MlG2QqvjGths+nq48TrUiKw==}
- engines: {node: '>=18'}
- cpu: [x64]
- os: [netbsd]
-
- '@esbuild/openbsd-arm64@0.25.4':
- resolution: {integrity: sha512-Ct2WcFEANlFDtp1nVAXSNBPDxyU+j7+tId//iHXU2f/lN5AmO4zLyhDcpR5Cz1r08mVxzt3Jpyt4PmXQ1O6+7A==}
- engines: {node: '>=18'}
- cpu: [arm64]
- os: [openbsd]
-
- '@esbuild/openbsd-x64@0.25.4':
- resolution: {integrity: sha512-xAGGhyOQ9Otm1Xu8NT1ifGLnA6M3sJxZ6ixylb+vIUVzvvd6GOALpwQrYrtlPouMqd/vSbgehz6HaVk4+7Afhw==}
- engines: {node: '>=18'}
- cpu: [x64]
- os: [openbsd]
-
- '@esbuild/sunos-x64@0.25.4':
- resolution: {integrity: sha512-Mw+tzy4pp6wZEK0+Lwr76pWLjrtjmJyUB23tHKqEDP74R3q95luY/bXqXZeYl4NYlvwOqoRKlInQialgCKy67Q==}
- engines: {node: '>=18'}
- cpu: [x64]
- os: [sunos]
-
- '@esbuild/win32-arm64@0.25.4':
- resolution: {integrity: sha512-AVUP428VQTSddguz9dO9ngb+E5aScyg7nOeJDrF1HPYu555gmza3bDGMPhmVXL8svDSoqPCsCPjb265yG/kLKQ==}
- engines: {node: '>=18'}
- cpu: [arm64]
- os: [win32]
-
- '@esbuild/win32-ia32@0.25.4':
- resolution: {integrity: sha512-i1sW+1i+oWvQzSgfRcxxG2k4I9n3O9NRqy8U+uugaT2Dy7kLO9Y7wI72haOahxceMX8hZAzgGou1FhndRldxRg==}
- engines: {node: '>=18'}
- cpu: [ia32]
- os: [win32]
-
- '@esbuild/win32-x64@0.25.4':
- resolution: {integrity: sha512-nOT2vZNw6hJ+z43oP1SPea/G/6AbN6X+bGNhNuq8NtRHy4wsMhw765IKLNmnjek7GvjWBYQ8Q5VBoYTFg9y1UQ==}
- engines: {node: '>=18'}
- cpu: [x64]
- os: [win32]
-
- '@img/sharp-darwin-arm64@0.33.5':
- resolution: {integrity: sha512-UT4p+iz/2H4twwAoLCqfA9UH5pI6DggwKEGuaPy7nCVQ8ZsiY5PIcrRvD1DzuY3qYL07NtIQcWnBSY/heikIFQ==}
- engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0}
- cpu: [arm64]
- os: [darwin]
-
- '@img/sharp-darwin-x64@0.33.5':
- resolution: {integrity: sha512-fyHac4jIc1ANYGRDxtiqelIbdWkIuQaI84Mv45KvGRRxSAa7o7d1ZKAOBaYbnepLC1WqxfpimdeWfvqqSGwR2Q==}
- engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0}
- cpu: [x64]
- os: [darwin]
-
- '@img/sharp-libvips-darwin-arm64@1.0.4':
- resolution: {integrity: sha512-XblONe153h0O2zuFfTAbQYAX2JhYmDHeWikp1LM9Hul9gVPjFY427k6dFEcOL72O01QxQsWi761svJ/ev9xEDg==}
- cpu: [arm64]
- os: [darwin]
-
- '@img/sharp-libvips-darwin-x64@1.0.4':
- resolution: {integrity: sha512-xnGR8YuZYfJGmWPvmlunFaWJsb9T/AO2ykoP3Fz/0X5XV2aoYBPkX6xqCQvUTKKiLddarLaxpzNe+b1hjeWHAQ==}
- cpu: [x64]
- os: [darwin]
-
- '@img/sharp-libvips-linux-arm64@1.0.4':
- resolution: {integrity: sha512-9B+taZ8DlyyqzZQnoeIvDVR/2F4EbMepXMc/NdVbkzsJbzkUjhXv/70GQJ7tdLA4YJgNP25zukcxpX2/SueNrA==}
- cpu: [arm64]
- os: [linux]
-
- '@img/sharp-libvips-linux-arm@1.0.5':
- resolution: {integrity: sha512-gvcC4ACAOPRNATg/ov8/MnbxFDJqf/pDePbBnuBDcjsI8PssmjoKMAz4LtLaVi+OnSb5FK/yIOamqDwGmXW32g==}
- cpu: [arm]
- os: [linux]
-
- '@img/sharp-libvips-linux-s390x@1.0.4':
- resolution: {integrity: sha512-u7Wz6ntiSSgGSGcjZ55im6uvTrOxSIS8/dgoVMoiGE9I6JAfU50yH5BoDlYA1tcuGS7g/QNtetJnxA6QEsCVTA==}
- cpu: [s390x]
- os: [linux]
-
- '@img/sharp-libvips-linux-x64@1.0.4':
- resolution: {integrity: sha512-MmWmQ3iPFZr0Iev+BAgVMb3ZyC4KeFc3jFxnNbEPas60e1cIfevbtuyf9nDGIzOaW9PdnDciJm+wFFaTlj5xYw==}
- cpu: [x64]
- os: [linux]
-
- '@img/sharp-libvips-linuxmusl-arm64@1.0.4':
- resolution: {integrity: sha512-9Ti+BbTYDcsbp4wfYib8Ctm1ilkugkA/uscUn6UXK1ldpC1JjiXbLfFZtRlBhjPZ5o1NCLiDbg8fhUPKStHoTA==}
- cpu: [arm64]
- os: [linux]
-
- '@img/sharp-libvips-linuxmusl-x64@1.0.4':
- resolution: {integrity: sha512-viYN1KX9m+/hGkJtvYYp+CCLgnJXwiQB39damAO7WMdKWlIhmYTfHjwSbQeUK/20vY154mwezd9HflVFM1wVSw==}
- cpu: [x64]
- os: [linux]
-
- '@img/sharp-linux-arm64@0.33.5':
- resolution: {integrity: sha512-JMVv+AMRyGOHtO1RFBiJy/MBsgz0x4AWrT6QoEVVTyh1E39TrCUpTRI7mx9VksGX4awWASxqCYLCV4wBZHAYxA==}
- engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0}
- cpu: [arm64]
- os: [linux]
-
- '@img/sharp-linux-arm@0.33.5':
- resolution: {integrity: sha512-JTS1eldqZbJxjvKaAkxhZmBqPRGmxgu+qFKSInv8moZ2AmT5Yib3EQ1c6gp493HvrvV8QgdOXdyaIBrhvFhBMQ==}
- engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0}
- cpu: [arm]
- os: [linux]
-
- '@img/sharp-linux-s390x@0.33.5':
- resolution: {integrity: sha512-y/5PCd+mP4CA/sPDKl2961b+C9d+vPAveS33s6Z3zfASk2j5upL6fXVPZi7ztePZ5CuH+1kW8JtvxgbuXHRa4Q==}
- engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0}
- cpu: [s390x]
- os: [linux]
-
- '@img/sharp-linux-x64@0.33.5':
- resolution: {integrity: sha512-opC+Ok5pRNAzuvq1AG0ar+1owsu842/Ab+4qvU879ippJBHvyY5n2mxF1izXqkPYlGuP/M556uh53jRLJmzTWA==}
- engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0}
- cpu: [x64]
- os: [linux]
-
- '@img/sharp-linuxmusl-arm64@0.33.5':
- resolution: {integrity: sha512-XrHMZwGQGvJg2V/oRSUfSAfjfPxO+4DkiRh6p2AFjLQztWUuY/o8Mq0eMQVIY7HJ1CDQUJlxGGZRw1a5bqmd1g==}
- engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0}
- cpu: [arm64]
- os: [linux]
-
- '@img/sharp-linuxmusl-x64@0.33.5':
- resolution: {integrity: sha512-WT+d/cgqKkkKySYmqoZ8y3pxx7lx9vVejxW/W4DOFMYVSkErR+w7mf2u8m/y4+xHe7yY9DAXQMWQhpnMuFfScw==}
- engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0}
- cpu: [x64]
- os: [linux]
-
- '@img/sharp-wasm32@0.33.5':
- resolution: {integrity: sha512-ykUW4LVGaMcU9lu9thv85CbRMAwfeadCJHRsg2GmeRa/cJxsVY9Rbd57JcMxBkKHag5U/x7TSBpScF4U8ElVzg==}
- engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0}
- cpu: [wasm32]
-
- '@img/sharp-win32-ia32@0.33.5':
- resolution: {integrity: sha512-T36PblLaTwuVJ/zw/LaH0PdZkRz5rd3SmMHX8GSmR7vtNSP5Z6bQkExdSK7xGWyxLw4sUknBuugTelgw2faBbQ==}
- engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0}
- cpu: [ia32]
- os: [win32]
-
- '@img/sharp-win32-x64@0.33.5':
- resolution: {integrity: sha512-MpY/o8/8kj+EcnxwvrP4aTJSWw/aZ7JIGR4aBeZkZw5B7/Jn+tY9/VNwtcoGmdT7GfggGIU4kygOMSbYnOrAbg==}
- engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0}
- cpu: [x64]
- os: [win32]
-
- '@jridgewell/resolve-uri@3.1.2':
- resolution: {integrity: sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==}
- engines: {node: '>=6.0.0'}
-
- '@jridgewell/sourcemap-codec@1.5.4':
- resolution: {integrity: sha512-VT2+G1VQs/9oz078bLrYbecdZKs912zQlkelYpuf+SXF+QvZDYJlbx/LSx+meSAwdDFnF8FVXW92AVjjkVmgFw==}
-
- '@jridgewell/trace-mapping@0.3.9':
- resolution: {integrity: sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==}
-
- '@poppinss/colors@4.1.5':
- resolution: {integrity: sha512-FvdDqtcRCtz6hThExcFOgW0cWX+xwSMWcRuQe5ZEb2m7cVQOAVZOIMt+/v9RxGiD9/OY16qJBXK4CVKWAPalBw==}
-
- '@poppinss/dumper@0.6.4':
- resolution: {integrity: sha512-iG0TIdqv8xJ3Lt9O8DrPRxw1MRLjNpoqiSGU03P/wNLP/s0ra0udPJ1J2Tx5M0J3H/cVyEgpbn8xUKRY9j59kQ==}
-
- '@poppinss/exception@1.2.2':
- resolution: {integrity: sha512-m7bpKCD4QMlFCjA/nKTs23fuvoVFoA83brRKmObCUNmi/9tVu8Ve3w4YQAnJu4q3Tjf5fr685HYIC/IA2zHRSg==}
-
- '@sindresorhus/is@7.0.2':
- resolution: {integrity: sha512-d9xRovfKNz1SKieM0qJdO+PQonjnnIfSNWfHYnBSJ9hkjm0ZPw6HlxscDXYstp3z+7V2GOFHc+J0CYrYTjqCJw==}
- engines: {node: '>=18'}
-
- '@speed-highlight/core@1.2.7':
- resolution: {integrity: sha512-0dxmVj4gxg3Jg879kvFS/msl4s9F3T9UXC1InxgOf7t5NvcPD97u/WTA5vL/IxWHMn7qSxBozqrnnE2wvl1m8g==}
-
- acorn-walk@8.3.2:
- resolution: {integrity: sha512-cjkyv4OtNCIeqhHrfS81QWXoCBPExR/J62oyEqepVw8WaQeSqpW2uhuLPh1m9eWhDuOo/jUXVTlifvesOWp/4A==}
- engines: {node: '>=0.4.0'}
-
- acorn@8.14.0:
- resolution: {integrity: sha512-cl669nCJTZBsL97OF4kUQm5g5hC2uihk0NxY3WENAC0TYdILVkAyHymAntgxGkl7K+t0cXIrH5siy5S4XkFycA==}
- engines: {node: '>=0.4.0'}
- hasBin: true
-
- blake3-wasm@2.1.5:
- resolution: {integrity: sha512-F1+K8EbfOZE49dtoPtmxUQrpXaBIl3ICvasLh+nJta0xkz+9kF/7uet9fLnwKqhDrmj6g+6K3Tw9yQPUg2ka5g==}
-
- color-convert@2.0.1:
- resolution: {integrity: sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==}
- engines: {node: '>=7.0.0'}
-
- color-name@1.1.4:
- resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==}
-
- color-string@1.9.1:
- resolution: {integrity: sha512-shrVawQFojnZv6xM40anx4CkoDP+fZsw/ZerEMsW/pyzsRbElpsL/DBVW7q3ExxwusdNXI3lXpuhEZkzs8p5Eg==}
-
- color@4.2.3:
- resolution: {integrity: sha512-1rXeuUUiGGrykh+CeBdu5Ie7OJwinCgQY0bc7GCRxy5xVHy+moaqkpL/jqQq0MtQOeYcrqEz4abc5f0KtU7W4A==}
- engines: {node: '>=12.5.0'}
-
- cookie@1.0.2:
- resolution: {integrity: sha512-9Kr/j4O16ISv8zBBhJoi4bXOYNTkFLOqSL3UDB0njXxCXNezjeyVrJyGOWtgfs/q2km1gwBcfH8q1yEGoMYunA==}
- engines: {node: '>=18'}
-
- defu@6.1.4:
- resolution: {integrity: sha512-mEQCMmwJu317oSz8CwdIOdwf3xMif1ttiM8LTufzc3g6kR+9Pe236twL8j3IYT1F7GfRgGcW6MWxzZjLIkuHIg==}
-
- detect-libc@2.0.4:
- resolution: {integrity: sha512-3UDv+G9CsCKO1WKMGw9fwq/SWJYbI0c5Y7LU1AXYoDdbhE2AHQ6N6Nb34sG8Fj7T5APy8qXDCKuuIHd1BR0tVA==}
- engines: {node: '>=8'}
-
- error-stack-parser-es@1.0.5:
- resolution: {integrity: sha512-5qucVt2XcuGMcEGgWI7i+yZpmpByQ8J1lHhcL7PwqCwu9FPP3VUXzT4ltHe5i2z9dePwEHcDVOAfSnHsOlCXRA==}
-
- esbuild@0.25.4:
- resolution: {integrity: sha512-8pgjLUcUjcgDg+2Q4NYXnPbo/vncAY4UmyaCm0jZevERqCHZIaWwdJHkf8XQtu4AxSKCdvrUbT0XUr1IdZzI8Q==}
- engines: {node: '>=18'}
- hasBin: true
-
- exit-hook@2.2.1:
- resolution: {integrity: sha512-eNTPlAD67BmP31LDINZ3U7HSF8l57TxOY2PmBJ1shpCvpnxBF93mWCE8YHBnXs8qiUZJc9WDcWIeC3a2HIAMfw==}
- engines: {node: '>=6'}
-
- exsolve@1.0.7:
- resolution: {integrity: sha512-VO5fQUzZtI6C+vx4w/4BWJpg3s/5l+6pRQEHzFRM8WFi4XffSP1Z+4qi7GbjWbvRQEbdIco5mIMq+zX4rPuLrw==}
-
- fsevents@2.3.3:
- resolution: {integrity: sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==}
- engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0}
- os: [darwin]
-
- glob-to-regexp@0.4.1:
- resolution: {integrity: sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw==}
-
- is-arrayish@0.3.2:
- resolution: {integrity: sha512-eVRqCvVlZbuw3GrM63ovNSNAeA1K16kaR/LRY/92w0zxQ5/1YzwblUX652i4Xs9RwAGjW9d9y6X88t8OaAJfWQ==}
-
- kleur@4.1.5:
- resolution: {integrity: sha512-o+NO+8WrRiQEE4/7nwRJhN1HWpVmJm511pBHUxPLtp0BUISzlBplORYSmTclCnJvQq2tKu/sgl3xVpkc7ZWuQQ==}
- engines: {node: '>=6'}
-
- mime@3.0.0:
- resolution: {integrity: sha512-jSCU7/VB1loIWBZe14aEYHU/+1UMEHoaO7qxCOVJOw9GgH72VAWppxNcjU+x9a2k3GSIBXNKxXQFqRvvZ7vr3A==}
- engines: {node: '>=10.0.0'}
- hasBin: true
-
- miniflare@4.20250712.0:
- resolution: {integrity: sha512-o7zYqG4pMi3gQTjiGhgZ82bQfexNwK+bzAaNlu8f7m3Kra4DcU5LC9nznfq2rfIBnUnMgwtU2VUfMlN1TuI8Og==}
- engines: {node: '>=18.0.0'}
- hasBin: true
-
- ohash@2.0.11:
- resolution: {integrity: sha512-RdR9FQrFwNBNXAr4GixM8YaRZRJ5PUWbKYbE5eOsrwAjJW0q2REGcf79oYPsLyskQCZG1PLN+S/K1V00joZAoQ==}
-
- path-to-regexp@6.3.0:
- resolution: {integrity: sha512-Yhpw4T9C6hPpgPeA28us07OJeqZ5EzQTkbfwuhsUg0c237RomFoETJgmp2sa3F/41gfLE6G5cqcYwznmeEeOlQ==}
-
- pathe@2.0.3:
- resolution: {integrity: sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w==}
-
- semver@7.7.2:
- resolution: {integrity: sha512-RF0Fw+rO5AMf9MAyaRXI4AV0Ulj5lMHqVxxdSgiVbixSCXoEmmX/jk0CuJw4+3SqroYO9VoUh+HcuJivvtJemA==}
- engines: {node: '>=10'}
- hasBin: true
-
- sharp@0.33.5:
- resolution: {integrity: sha512-haPVm1EkS9pgvHrQ/F3Xy+hgcuMV0Wm9vfIBSiwZ05k+xgb0PkBQpGsAA/oWdDobNaZTH5ppvHtzCFbnSEwHVw==}
- engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0}
-
- simple-swizzle@0.2.2:
- resolution: {integrity: sha512-JA//kQgZtbuY83m+xT+tXJkmJncGMTFT+C+g2h2R9uxkYIrE2yy9sgmcLhCnw57/WSD+Eh3J97FPEDFnbXnDUg==}
-
- stoppable@1.1.0:
- resolution: {integrity: sha512-KXDYZ9dszj6bzvnEMRYvxgeTHU74QBFL54XKtP3nyMuJ81CFYtABZ3bAzL2EdFUaEwJOBOgENyFj3R7oTzDyyw==}
- engines: {node: '>=4', npm: '>=6'}
-
- supports-color@10.0.0:
- resolution: {integrity: sha512-HRVVSbCCMbj7/kdWF9Q+bbckjBHLtHMEoJWlkmYzzdwhYMkjkOwubLM6t7NbWKjgKamGDrWL1++KrjUO1t9oAQ==}
- engines: {node: '>=18'}
-
- tslib@2.8.1:
- resolution: {integrity: sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==}
-
- typescript@5.8.3:
- resolution: {integrity: sha512-p1diW6TqL9L07nNxvRMM7hMMw4c5XOo/1ibL4aAIGmSAt9slTE1Xgw5KWuof2uTOvCg9BY7ZRi+GaF+7sfgPeQ==}
- engines: {node: '>=14.17'}
- hasBin: true
-
- ufo@1.6.1:
- resolution: {integrity: sha512-9a4/uxlTWJ4+a5i0ooc1rU7C7YOw3wT+UGqdeNNHWnOF9qcMBgLRS+4IYUqbczewFx4mLEig6gawh7X6mFlEkA==}
-
- undici@7.12.0:
- resolution: {integrity: sha512-GrKEsc3ughskmGA9jevVlIOPMiiAHJ4OFUtaAH+NhfTUSiZ1wMPIQqQvAJUrJspFXJt3EBWgpAeoHEDVT1IBug==}
- engines: {node: '>=20.18.1'}
-
- unenv@2.0.0-rc.17:
- resolution: {integrity: sha512-B06u0wXkEd+o5gOCMl/ZHl5cfpYbDZKAT+HWTL+Hws6jWu7dCiqBBXXXzMFcFVJb8D4ytAnYmxJA83uwOQRSsg==}
-
- workerd@1.20250712.0:
- resolution: {integrity: sha512-7h+k1OxREpiZW0849g0uQNexRWMcs5i5gUGhJzCY8nIx6Tv4D/ndlXJ47lEFj7/LQdp165IL9dM2D5uDiedZrg==}
- engines: {node: '>=16'}
- hasBin: true
-
- wrangler@4.25.0:
- resolution: {integrity: sha512-SepXQbzWkdp0O7qAx3i0go+fw5I0VkDqLV2G3ewbffO5k8kpvuCkhalS23KO+7+o8+Oa3vfC7x+16IL3rj2n4w==}
- engines: {node: '>=18.0.0'}
- hasBin: true
- peerDependencies:
- '@cloudflare/workers-types': ^4.20250712.0
- peerDependenciesMeta:
- '@cloudflare/workers-types':
- optional: true
-
- ws@8.18.0:
- resolution: {integrity: sha512-8VbfWfHLbbwu3+N6OKsOMpBdT4kXPDDB9cJk2bJ6mh9ucxdlnNvH1e+roYkKmN9Nxw2yjz7VzeO9oOz2zJ04Pw==}
- engines: {node: '>=10.0.0'}
- peerDependencies:
- bufferutil: ^4.0.1
- utf-8-validate: '>=5.0.2'
- peerDependenciesMeta:
- bufferutil:
- optional: true
- utf-8-validate:
- optional: true
-
- youch-core@0.3.3:
- resolution: {integrity: sha512-ho7XuGjLaJ2hWHoK8yFnsUGy2Y5uDpqSTq1FkHLK4/oqKtyUU1AFbOOxY4IpC9f0fTLjwYbslUz0Po5BpD1wrA==}
-
- youch@4.1.0-beta.10:
- resolution: {integrity: sha512-rLfVLB4FgQneDr0dv1oddCVZmKjcJ6yX6mS4pU82Mq/Dt9a3cLZQ62pDBL4AUO+uVrCvtWz3ZFUL2HFAFJ/BXQ==}
-
- zod@3.22.3:
- resolution: {integrity: sha512-EjIevzuJRiRPbVH4mGc8nApb/lVLKVpmUhAaR5R5doKGfAnGJ6Gr3CViAVjP+4FWSxCsybeWQdcgCtbX+7oZug==}
-
-snapshots:
-
- '@cloudflare/kv-asset-handler@0.4.0':
- dependencies:
- mime: 3.0.0
-
- '@cloudflare/unenv-preset@2.3.3(unenv@2.0.0-rc.17)(workerd@1.20250712.0)':
- dependencies:
- unenv: 2.0.0-rc.17
- optionalDependencies:
- workerd: 1.20250712.0
-
- '@cloudflare/workerd-darwin-64@1.20250712.0':
- optional: true
-
- '@cloudflare/workerd-darwin-arm64@1.20250712.0':
- optional: true
-
- '@cloudflare/workerd-linux-64@1.20250712.0':
- optional: true
-
- '@cloudflare/workerd-linux-arm64@1.20250712.0':
- optional: true
-
- '@cloudflare/workerd-windows-64@1.20250712.0':
- optional: true
-
- '@cloudflare/workers-types@4.20250730.0': {}
-
- '@cspotcode/source-map-support@0.8.1':
- dependencies:
- '@jridgewell/trace-mapping': 0.3.9
-
- '@emnapi/runtime@1.4.5':
- dependencies:
- tslib: 2.8.1
- optional: true
-
- '@esbuild/aix-ppc64@0.25.4':
- optional: true
-
- '@esbuild/android-arm64@0.25.4':
- optional: true
-
- '@esbuild/android-arm@0.25.4':
- optional: true
-
- '@esbuild/android-x64@0.25.4':
- optional: true
-
- '@esbuild/darwin-arm64@0.25.4':
- optional: true
-
- '@esbuild/darwin-x64@0.25.4':
- optional: true
-
- '@esbuild/freebsd-arm64@0.25.4':
- optional: true
-
- '@esbuild/freebsd-x64@0.25.4':
- optional: true
-
- '@esbuild/linux-arm64@0.25.4':
- optional: true
-
- '@esbuild/linux-arm@0.25.4':
- optional: true
-
- '@esbuild/linux-ia32@0.25.4':
- optional: true
-
- '@esbuild/linux-loong64@0.25.4':
- optional: true
-
- '@esbuild/linux-mips64el@0.25.4':
- optional: true
-
- '@esbuild/linux-ppc64@0.25.4':
- optional: true
-
- '@esbuild/linux-riscv64@0.25.4':
- optional: true
-
- '@esbuild/linux-s390x@0.25.4':
- optional: true
-
- '@esbuild/linux-x64@0.25.4':
- optional: true
-
- '@esbuild/netbsd-arm64@0.25.4':
- optional: true
-
- '@esbuild/netbsd-x64@0.25.4':
- optional: true
-
- '@esbuild/openbsd-arm64@0.25.4':
- optional: true
-
- '@esbuild/openbsd-x64@0.25.4':
- optional: true
-
- '@esbuild/sunos-x64@0.25.4':
- optional: true
-
- '@esbuild/win32-arm64@0.25.4':
- optional: true
-
- '@esbuild/win32-ia32@0.25.4':
- optional: true
-
- '@esbuild/win32-x64@0.25.4':
- optional: true
-
- '@img/sharp-darwin-arm64@0.33.5':
- optionalDependencies:
- '@img/sharp-libvips-darwin-arm64': 1.0.4
- optional: true
-
- '@img/sharp-darwin-x64@0.33.5':
- optionalDependencies:
- '@img/sharp-libvips-darwin-x64': 1.0.4
- optional: true
-
- '@img/sharp-libvips-darwin-arm64@1.0.4':
- optional: true
-
- '@img/sharp-libvips-darwin-x64@1.0.4':
- optional: true
-
- '@img/sharp-libvips-linux-arm64@1.0.4':
- optional: true
-
- '@img/sharp-libvips-linux-arm@1.0.5':
- optional: true
-
- '@img/sharp-libvips-linux-s390x@1.0.4':
- optional: true
-
- '@img/sharp-libvips-linux-x64@1.0.4':
- optional: true
-
- '@img/sharp-libvips-linuxmusl-arm64@1.0.4':
- optional: true
-
- '@img/sharp-libvips-linuxmusl-x64@1.0.4':
- optional: true
-
- '@img/sharp-linux-arm64@0.33.5':
- optionalDependencies:
- '@img/sharp-libvips-linux-arm64': 1.0.4
- optional: true
-
- '@img/sharp-linux-arm@0.33.5':
- optionalDependencies:
- '@img/sharp-libvips-linux-arm': 1.0.5
- optional: true
-
- '@img/sharp-linux-s390x@0.33.5':
- optionalDependencies:
- '@img/sharp-libvips-linux-s390x': 1.0.4
- optional: true
-
- '@img/sharp-linux-x64@0.33.5':
- optionalDependencies:
- '@img/sharp-libvips-linux-x64': 1.0.4
- optional: true
-
- '@img/sharp-linuxmusl-arm64@0.33.5':
- optionalDependencies:
- '@img/sharp-libvips-linuxmusl-arm64': 1.0.4
- optional: true
-
- '@img/sharp-linuxmusl-x64@0.33.5':
- optionalDependencies:
- '@img/sharp-libvips-linuxmusl-x64': 1.0.4
- optional: true
-
- '@img/sharp-wasm32@0.33.5':
- dependencies:
- '@emnapi/runtime': 1.4.5
- optional: true
-
- '@img/sharp-win32-ia32@0.33.5':
- optional: true
-
- '@img/sharp-win32-x64@0.33.5':
- optional: true
-
- '@jridgewell/resolve-uri@3.1.2': {}
-
- '@jridgewell/sourcemap-codec@1.5.4': {}
-
- '@jridgewell/trace-mapping@0.3.9':
- dependencies:
- '@jridgewell/resolve-uri': 3.1.2
- '@jridgewell/sourcemap-codec': 1.5.4
-
- '@poppinss/colors@4.1.5':
- dependencies:
- kleur: 4.1.5
-
- '@poppinss/dumper@0.6.4':
- dependencies:
- '@poppinss/colors': 4.1.5
- '@sindresorhus/is': 7.0.2
- supports-color: 10.0.0
-
- '@poppinss/exception@1.2.2': {}
-
- '@sindresorhus/is@7.0.2': {}
-
- '@speed-highlight/core@1.2.7': {}
-
- acorn-walk@8.3.2: {}
-
- acorn@8.14.0: {}
-
- blake3-wasm@2.1.5: {}
-
- color-convert@2.0.1:
- dependencies:
- color-name: 1.1.4
-
- color-name@1.1.4: {}
-
- color-string@1.9.1:
- dependencies:
- color-name: 1.1.4
- simple-swizzle: 0.2.2
-
- color@4.2.3:
- dependencies:
- color-convert: 2.0.1
- color-string: 1.9.1
-
- cookie@1.0.2: {}
-
- defu@6.1.4: {}
-
- detect-libc@2.0.4: {}
-
- error-stack-parser-es@1.0.5: {}
-
- esbuild@0.25.4:
- optionalDependencies:
- '@esbuild/aix-ppc64': 0.25.4
- '@esbuild/android-arm': 0.25.4
- '@esbuild/android-arm64': 0.25.4
- '@esbuild/android-x64': 0.25.4
- '@esbuild/darwin-arm64': 0.25.4
- '@esbuild/darwin-x64': 0.25.4
- '@esbuild/freebsd-arm64': 0.25.4
- '@esbuild/freebsd-x64': 0.25.4
- '@esbuild/linux-arm': 0.25.4
- '@esbuild/linux-arm64': 0.25.4
- '@esbuild/linux-ia32': 0.25.4
- '@esbuild/linux-loong64': 0.25.4
- '@esbuild/linux-mips64el': 0.25.4
- '@esbuild/linux-ppc64': 0.25.4
- '@esbuild/linux-riscv64': 0.25.4
- '@esbuild/linux-s390x': 0.25.4
- '@esbuild/linux-x64': 0.25.4
- '@esbuild/netbsd-arm64': 0.25.4
- '@esbuild/netbsd-x64': 0.25.4
- '@esbuild/openbsd-arm64': 0.25.4
- '@esbuild/openbsd-x64': 0.25.4
- '@esbuild/sunos-x64': 0.25.4
- '@esbuild/win32-arm64': 0.25.4
- '@esbuild/win32-ia32': 0.25.4
- '@esbuild/win32-x64': 0.25.4
-
- exit-hook@2.2.1: {}
-
- exsolve@1.0.7: {}
-
- fsevents@2.3.3:
- optional: true
-
- glob-to-regexp@0.4.1: {}
-
- is-arrayish@0.3.2: {}
-
- kleur@4.1.5: {}
-
- mime@3.0.0: {}
-
- miniflare@4.20250712.0:
- dependencies:
- '@cspotcode/source-map-support': 0.8.1
- acorn: 8.14.0
- acorn-walk: 8.3.2
- exit-hook: 2.2.1
- glob-to-regexp: 0.4.1
- sharp: 0.33.5
- stoppable: 1.1.0
- undici: 7.12.0
- workerd: 1.20250712.0
- ws: 8.18.0
- youch: 4.1.0-beta.10
- zod: 3.22.3
- transitivePeerDependencies:
- - bufferutil
- - utf-8-validate
-
- ohash@2.0.11: {}
-
- path-to-regexp@6.3.0: {}
-
- pathe@2.0.3: {}
-
- semver@7.7.2: {}
-
- sharp@0.33.5:
- dependencies:
- color: 4.2.3
- detect-libc: 2.0.4
- semver: 7.7.2
- optionalDependencies:
- '@img/sharp-darwin-arm64': 0.33.5
- '@img/sharp-darwin-x64': 0.33.5
- '@img/sharp-libvips-darwin-arm64': 1.0.4
- '@img/sharp-libvips-darwin-x64': 1.0.4
- '@img/sharp-libvips-linux-arm': 1.0.5
- '@img/sharp-libvips-linux-arm64': 1.0.4
- '@img/sharp-libvips-linux-s390x': 1.0.4
- '@img/sharp-libvips-linux-x64': 1.0.4
- '@img/sharp-libvips-linuxmusl-arm64': 1.0.4
- '@img/sharp-libvips-linuxmusl-x64': 1.0.4
- '@img/sharp-linux-arm': 0.33.5
- '@img/sharp-linux-arm64': 0.33.5
- '@img/sharp-linux-s390x': 0.33.5
- '@img/sharp-linux-x64': 0.33.5
- '@img/sharp-linuxmusl-arm64': 0.33.5
- '@img/sharp-linuxmusl-x64': 0.33.5
- '@img/sharp-wasm32': 0.33.5
- '@img/sharp-win32-ia32': 0.33.5
- '@img/sharp-win32-x64': 0.33.5
-
- simple-swizzle@0.2.2:
- dependencies:
- is-arrayish: 0.3.2
-
- stoppable@1.1.0: {}
-
- supports-color@10.0.0: {}
-
- tslib@2.8.1:
- optional: true
-
- typescript@5.8.3: {}
-
- ufo@1.6.1: {}
-
- undici@7.12.0: {}
-
- unenv@2.0.0-rc.17:
- dependencies:
- defu: 6.1.4
- exsolve: 1.0.7
- ohash: 2.0.11
- pathe: 2.0.3
- ufo: 1.6.1
-
- workerd@1.20250712.0:
- optionalDependencies:
- '@cloudflare/workerd-darwin-64': 1.20250712.0
- '@cloudflare/workerd-darwin-arm64': 1.20250712.0
- '@cloudflare/workerd-linux-64': 1.20250712.0
- '@cloudflare/workerd-linux-arm64': 1.20250712.0
- '@cloudflare/workerd-windows-64': 1.20250712.0
-
- wrangler@4.25.0(@cloudflare/workers-types@4.20250730.0):
- dependencies:
- '@cloudflare/kv-asset-handler': 0.4.0
- '@cloudflare/unenv-preset': 2.3.3(unenv@2.0.0-rc.17)(workerd@1.20250712.0)
- blake3-wasm: 2.1.5
- esbuild: 0.25.4
- miniflare: 4.20250712.0
- path-to-regexp: 6.3.0
- unenv: 2.0.0-rc.17
- workerd: 1.20250712.0
- optionalDependencies:
- '@cloudflare/workers-types': 4.20250730.0
- fsevents: 2.3.3
- transitivePeerDependencies:
- - bufferutil
- - utf-8-validate
-
- ws@8.18.0: {}
-
- youch-core@0.3.3:
- dependencies:
- '@poppinss/exception': 1.2.2
- error-stack-parser-es: 1.0.5
-
- youch@4.1.0-beta.10:
- dependencies:
- '@poppinss/colors': 4.1.5
- '@poppinss/dumper': 0.6.4
- '@speed-highlight/core': 1.2.7
- cookie: 1.0.2
- youch-core: 0.3.3
-
- zod@3.22.3: {}
diff --git a/package.json b/package.json
index 629ae2bf..1479a98b 100644
--- a/package.json
+++ b/package.json
@@ -11,23 +11,23 @@
"dev:runt": "./scripts/start-runt-dev.sh",
"dev": "vite",
"dev:web": "vite --no-open",
- "dev:iframe": "cd iframe-outputs && vite --port 8000",
+ "dev:iframe": "pnpm --filter @anode/iframe-outputs dev",
"dev:scan": "pnpm run dev & npx react-scan@latest localhost:5173",
"dev:auth": "vite --mode auth",
"predev:sync": "pnpm run db:migrate",
"dev:sync": "wrangler dev",
"dev:runtime": "./scripts/dev-runtime.sh",
- "build:iframe": "cd iframe-outputs && vite build",
- "build": "vite build --mode development",
+ "build:iframe": "pnpm --filter @anode/iframe-outputs build",
+ "build": "pnpm --filter @anode/shared build && vite build --mode development",
"use-runt": "./scripts/use-runt.sh",
- "build:preview": "vite build --mode preview",
- "build:production": "./scripts/optimize-build.sh && vite build --mode production",
- "build:production:fast": "vite build --mode production",
+ "build:preview": "pnpm --filter @anode/shared build && vite build --mode preview",
+ "build:production": "pnpm --filter @anode/shared build && ./scripts/optimize-build.sh && vite build --mode production",
+ "build:production:fast": "pnpm --filter @anode/shared build && vite build --mode production",
"deploy:preview": "CLOUDFLARE_ENV=preview pnpm wrangler d1 migrations apply DB --env preview --remote && pnpm wrangler deploy --env preview",
"deploy:production": "CLOUDFLARE_ENV=production pnpm wrangler d1 migrations apply DB --env production --remote && pnpm wrangler deploy",
"preview": "vite preview",
- "clean": "rm -rf dist node_modules/.vite node_modules/.vite-main node_modules/.vite-wrangler",
- "clean:cache": "rm -rf dist node_modules/.vite node_modules/.vite-main node_modules/.vite-wrangler node_modules/.pnpm-store ~/.pnpm-cache",
+ "clean": "rm -rf dist node_modules/.vite node_modules/.vite-main node_modules/.vite-wrangler && pnpm -r clean",
+ "clean:cache": "rm -rf dist node_modules/.vite node_modules/.vite-main node_modules/.vite-wrangler node_modules/.pnpm-store ~/.pnpm-cache && pnpm -r clean",
"test": "vitest",
"test:ui": "vitest --ui",
"test:run": "vitest run",
@@ -35,11 +35,11 @@
"test:watch": "vitest --watch",
"test:integration": "vitest run test/integration/",
"test:debug": "DEBUG_TESTS=true vitest run",
- "test:iframe": "http-server ./iframe-outputs -p 3000 -o test-iframe.html",
+ "test:iframe": "http-server ./packages/iframe-outputs -p 3000 -o test-iframe.html",
"db:migrate": "echo y | wrangler d1 migrations apply DB",
- "type-check": "tsc --noEmit && tsc --noEmit --project tsconfig.test.json",
- "lint": "eslint src/ backend/ iframe-outputs/",
- "lint:check": "eslint src/ backend/ iframe-outputs/ --max-warnings 0",
+ "type-check": "tsc --noEmit && tsc --noEmit --project tsconfig.test.json && pnpm -r type-check",
+ "lint": "eslint src/ backend/ packages/",
+ "lint:check": "eslint src/ backend/ packages/ --max-warnings 0",
"format": "prettier --write .",
"format:check": "prettier --check .",
"check": "pnpm type-check && pnpm lint && pnpm format:check",
@@ -75,6 +75,7 @@
"@radix-ui/react-slot": "^1.2.3",
"@radix-ui/react-tooltip": "^1.1.6",
"@react-spring/web": "^10.0.1",
+ "@anode/shared": "workspace:*",
"@runt/schema": "jsr:^0.13.0",
"@tanstack/react-query": "^5.85.5",
"@tanstack/react-query-devtools": "^5.85.5",
diff --git a/iframe-outputs/README.md b/packages/iframe-outputs/README.md
similarity index 100%
rename from iframe-outputs/README.md
rename to packages/iframe-outputs/README.md
diff --git a/packages/iframe-outputs/package.json b/packages/iframe-outputs/package.json
new file mode 100644
index 00000000..b96099d1
--- /dev/null
+++ b/packages/iframe-outputs/package.json
@@ -0,0 +1,53 @@
+{
+ "name": "@anode/iframe-outputs",
+ "version": "0.2.0",
+ "type": "module",
+ "private": true,
+ "description": "Isolated iframe content server for Anode user-generated outputs",
+ "engines": {
+ "node": ">=23.0.0",
+ "pnpm": ">=10.9.0"
+ },
+ "scripts": {
+ "dev": "vite --port 8000",
+ "build": "vite build",
+ "preview": "vite preview",
+ "deploy": "cd worker && wrangler deploy --env production",
+ "deploy:production": "cd worker && wrangler deploy --env production",
+ "deploy:preview": "cd worker && wrangler deploy --env preview",
+ "deploy:preview-dry-run": "cd worker && wrangler deploy --env preview --dry-run",
+ "deploy:production-dry-run": "cd worker && wrangler deploy --env production --dry-run",
+ "logs": "cd worker && wrangler tail --env production",
+ "logs:preview": "cd worker && wrangler tail --env preview",
+ "type-check": "tsc --noEmit",
+ "test": "echo 'No tests yet'",
+ "clean": "rm -rf dist worker/dist node_modules/.vite"
+ },
+ "dependencies": {
+ "@anode/shared": "workspace:*",
+ "modern-normalize": "^3.0.1",
+ "react": "19.0.0",
+ "react-dom": "19.0.0",
+ "tw-animate-css": "^1.3.4"
+ },
+ "devDependencies": {
+ "@cloudflare/workers-types": "^4.20250813.0",
+ "@tailwindcss/typography": "^0.5.16",
+ "@tailwindcss/vite": "^4.1.10",
+ "@types/react": "^19.1.8",
+ "@types/react-dom": "^19.1.6",
+ "@vitejs/plugin-react": "^4.5.2",
+ "tailwindcss": "^4.1.10",
+ "typescript": "^5.8.3",
+ "vite": "^6.3.5",
+ "wrangler": "4.27.0"
+ },
+ "keywords": [
+ "iframe",
+ "sandbox",
+ "user-content",
+ "cloudflare-worker"
+ ],
+ "author": "Runt Team",
+ "license": "MIT"
+}
diff --git a/iframe-outputs/src/components/IframeReactApp.tsx b/packages/iframe-outputs/src/components/IframeReactApp.tsx
similarity index 64%
rename from iframe-outputs/src/components/IframeReactApp.tsx
rename to packages/iframe-outputs/src/components/IframeReactApp.tsx
index 8b3c5c84..bbe53c1f 100644
--- a/iframe-outputs/src/components/IframeReactApp.tsx
+++ b/packages/iframe-outputs/src/components/IframeReactApp.tsx
@@ -1,5 +1,4 @@
-import { SingleOutput } from "@/components/outputs/shared-with-iframe/SingleOutput";
-import { useIframeCommsChild } from "@/components/outputs/shared-with-iframe/comms";
+import { SingleOutput, useIframeCommsChild } from "@anode/shared";
import React from "react";
export const IframeReactApp: React.FC = () => {
diff --git a/iframe-outputs/src/react-main.tsx b/packages/iframe-outputs/src/react-main.tsx
similarity index 89%
rename from iframe-outputs/src/react-main.tsx
rename to packages/iframe-outputs/src/react-main.tsx
index ee0926ce..0fa9f5f8 100644
--- a/iframe-outputs/src/react-main.tsx
+++ b/packages/iframe-outputs/src/react-main.tsx
@@ -1,7 +1,7 @@
import { createRoot } from "react-dom/client";
import { IframeReactApp } from "./components/IframeReactApp";
import "./style.css";
-import { sendFromIframe } from "@/components/outputs/shared-with-iframe/comms";
+import { sendFromIframe } from "@anode/shared";
// Main React initialization for iframe outputs
function initializeReactIframe() {
diff --git a/iframe-outputs/src/react.html b/packages/iframe-outputs/src/react.html
similarity index 100%
rename from iframe-outputs/src/react.html
rename to packages/iframe-outputs/src/react.html
diff --git a/iframe-outputs/src/style.css b/packages/iframe-outputs/src/style.css
similarity index 97%
rename from iframe-outputs/src/style.css
rename to packages/iframe-outputs/src/style.css
index 7a90ea6a..de672be0 100644
--- a/iframe-outputs/src/style.css
+++ b/packages/iframe-outputs/src/style.css
@@ -13,8 +13,8 @@ Docs: https://tailwindcss.com/docs/preflight#overview
@import "tw-animate-css";
@plugin "@tailwindcss/typography";
-@source "../../src/components/outputs/shared-with-iframe";
-@source "../../src/components/ui";
+@source "../shared/components";
+@source "../shared/ui";
:root {
--dataframe-border: 1px solid #e5e7eb;
diff --git a/packages/iframe-outputs/tailwind.config.js b/packages/iframe-outputs/tailwind.config.js
new file mode 100644
index 00000000..9250b464
--- /dev/null
+++ b/packages/iframe-outputs/tailwind.config.js
@@ -0,0 +1,65 @@
+import typography from "@tailwindcss/typography";
+
+/** @type {import('tailwindcss').Config} */
+export default {
+ content: ["./src/**/*.{js,ts,jsx,tsx}", "../shared/**/*.{js,ts,jsx,tsx}"],
+ theme: {
+ extend: {
+ fontFamily: {
+ sans: [
+ "-apple-system",
+ "BlinkMacSystemFont",
+ "Segoe UI",
+ "Roboto",
+ "Helvetica",
+ "Arial",
+ "sans-serif",
+ "Apple Color Emoji",
+ "Segoe UI Emoji",
+ "Segoe UI Symbol",
+ ],
+ },
+ colors: {
+ border: "hsl(var(--border))",
+ input: "hsl(var(--input))",
+ ring: "hsl(var(--ring))",
+ background: "hsl(var(--background))",
+ foreground: "hsl(var(--foreground))",
+ primary: {
+ DEFAULT: "hsl(var(--primary))",
+ foreground: "hsl(var(--primary-foreground))",
+ },
+ secondary: {
+ DEFAULT: "hsl(var(--secondary))",
+ foreground: "hsl(var(--secondary-foreground))",
+ },
+ destructive: {
+ DEFAULT: "hsl(var(--destructive))",
+ foreground: "hsl(var(--destructive-foreground))",
+ },
+ muted: {
+ DEFAULT: "hsl(var(--muted))",
+ foreground: "hsl(var(--muted-foreground))",
+ },
+ accent: {
+ DEFAULT: "hsl(var(--accent))",
+ foreground: "hsl(var(--accent-foreground))",
+ },
+ popover: {
+ DEFAULT: "hsl(var(--popover))",
+ foreground: "hsl(var(--popover-foreground))",
+ },
+ card: {
+ DEFAULT: "hsl(var(--card))",
+ foreground: "hsl(var(--card-foreground))",
+ },
+ },
+ borderRadius: {
+ lg: "var(--radius)",
+ md: "calc(var(--radius) - 2px)",
+ sm: "calc(var(--radius) - 4px)",
+ },
+ },
+ },
+ plugins: [typography],
+};
diff --git a/iframe-outputs/test-iframe.html b/packages/iframe-outputs/test-iframe.html
similarity index 100%
rename from iframe-outputs/test-iframe.html
rename to packages/iframe-outputs/test-iframe.html
diff --git a/packages/iframe-outputs/tsconfig.json b/packages/iframe-outputs/tsconfig.json
new file mode 100644
index 00000000..b9140571
--- /dev/null
+++ b/packages/iframe-outputs/tsconfig.json
@@ -0,0 +1,39 @@
+{
+ "compilerOptions": {
+ "target": "ES2020",
+ "useDefineForClassFields": true,
+ "lib": ["ES2020", "DOM", "DOM.Iterable"],
+ "module": "ESNext",
+ "skipLibCheck": true,
+ "moduleResolution": "bundler",
+ "allowImportingTsExtensions": true,
+ "resolveJsonModule": true,
+ "isolatedModules": true,
+ "noEmit": true,
+ "jsx": "react-jsx",
+ "strict": true,
+ "noUnusedLocals": true,
+ "noUnusedParameters": true,
+ "noFallthroughCasesInSwitch": true,
+ "paths": {
+ "@/*": ["./src/*"],
+ "@anode/shared": ["../shared/index.ts"],
+ "@anode/shared/*": ["../shared/*"]
+ }
+ },
+ "include": [
+ "src/**/*",
+ "worker/**/*"
+ ],
+ "exclude": [
+ "node_modules",
+ "dist",
+ "worker/dist",
+ "legacy"
+ ],
+ "references": [
+ {
+ "path": "../shared"
+ }
+ ]
+}
diff --git a/iframe-outputs/vite.config.ts b/packages/iframe-outputs/vite.config.ts
similarity index 66%
rename from iframe-outputs/vite.config.ts
rename to packages/iframe-outputs/vite.config.ts
index aeaa7021..72d2c3e7 100644
--- a/iframe-outputs/vite.config.ts
+++ b/packages/iframe-outputs/vite.config.ts
@@ -5,10 +5,10 @@ import tailwindcss from "@tailwindcss/vite";
export default defineConfig({
root: "src",
- plugins: [react(), tailwindcss()] as any,
+ plugins: [react(), tailwindcss()],
resolve: {
alias: {
- "@": resolve(__dirname, "../src"),
+ "@": resolve(__dirname, "./src"),
},
},
build: {
@@ -16,9 +16,15 @@ export default defineConfig({
emptyOutDir: true,
rollupOptions: {
input: {
- // TODO: add a basic index.html entry point too!
react: resolve(__dirname, "src/react.html"),
},
},
},
+ server: {
+ port: 8000,
+ strictPort: true,
+ },
+ optimizeDeps: {
+ include: ["react", "react-dom", "@anode/shared"],
+ },
});
diff --git a/iframe-outputs/worker/tsconfig.json b/packages/iframe-outputs/worker/tsconfig.json
similarity index 100%
rename from iframe-outputs/worker/tsconfig.json
rename to packages/iframe-outputs/worker/tsconfig.json
diff --git a/iframe-outputs/worker/worker.ts b/packages/iframe-outputs/worker/worker.ts
similarity index 100%
rename from iframe-outputs/worker/worker.ts
rename to packages/iframe-outputs/worker/worker.ts
diff --git a/iframe-outputs/worker/wrangler.toml b/packages/iframe-outputs/worker/wrangler.toml
similarity index 100%
rename from iframe-outputs/worker/wrangler.toml
rename to packages/iframe-outputs/worker/wrangler.toml
diff --git a/src/components/outputs/shared-with-iframe/AiToolApprovalOutput.tsx b/packages/shared/components/AiToolApprovalOutput.tsx
similarity index 98%
rename from src/components/outputs/shared-with-iframe/AiToolApprovalOutput.tsx
rename to packages/shared/components/AiToolApprovalOutput.tsx
index 74b968ed..37239731 100644
--- a/src/components/outputs/shared-with-iframe/AiToolApprovalOutput.tsx
+++ b/packages/shared/components/AiToolApprovalOutput.tsx
@@ -1,6 +1,6 @@
import React from "react";
-import { Button } from "../../ui/button";
-import { Card } from "../../ui/card";
+import { Button } from "../ui/button";
+import { Card } from "../ui/card";
import {
Shield,
ShieldCheck,
diff --git a/src/components/outputs/shared-with-iframe/AiToolCallOutput.tsx b/packages/shared/components/AiToolCallOutput.tsx
similarity index 98%
rename from src/components/outputs/shared-with-iframe/AiToolCallOutput.tsx
rename to packages/shared/components/AiToolCallOutput.tsx
index 33cd37ce..89d574f2 100644
--- a/src/components/outputs/shared-with-iframe/AiToolCallOutput.tsx
+++ b/packages/shared/components/AiToolCallOutput.tsx
@@ -2,7 +2,7 @@ import React from "react";
import { Prism as SyntaxHighlighter } from "react-syntax-highlighter";
import { oneLight } from "react-syntax-highlighter/dist/esm/styles/prism";
import { ChevronDown, Edit, FilePlus, Info } from "lucide-react";
-import { AiToolCallData } from "@/schema";
+import { AiToolCallData } from "../schema";
interface AiToolCallOutputProps {
toolData: AiToolCallData;
diff --git a/src/components/outputs/shared-with-iframe/AiToolResultOutput.tsx b/packages/shared/components/AiToolResultOutput.tsx
similarity index 96%
rename from src/components/outputs/shared-with-iframe/AiToolResultOutput.tsx
rename to packages/shared/components/AiToolResultOutput.tsx
index a23940cf..69bd7886 100644
--- a/src/components/outputs/shared-with-iframe/AiToolResultOutput.tsx
+++ b/packages/shared/components/AiToolResultOutput.tsx
@@ -1,6 +1,6 @@
import React from "react";
import { CheckCircle, XCircle, Clock, Info } from "lucide-react";
-import { AiToolResultData } from "@/schema";
+import { AiToolResultData } from "../schema";
interface AiToolResultOutputProps {
resultData: AiToolResultData;
diff --git a/src/components/outputs/shared-with-iframe/AnsiOutput.tsx b/packages/shared/components/AnsiOutput.tsx
similarity index 100%
rename from src/components/outputs/shared-with-iframe/AnsiOutput.tsx
rename to packages/shared/components/AnsiOutput.tsx
diff --git a/src/components/outputs/shared-with-iframe/HtmlOutput.tsx b/packages/shared/components/HtmlOutput.tsx
similarity index 93%
rename from src/components/outputs/shared-with-iframe/HtmlOutput.tsx
rename to packages/shared/components/HtmlOutput.tsx
index ccf49189..5530c8b2 100644
--- a/src/components/outputs/shared-with-iframe/HtmlOutput.tsx
+++ b/packages/shared/components/HtmlOutput.tsx
@@ -1,4 +1,4 @@
-import { throwIfNotInIframe } from "@/util/iframe";
+import { throwIfNotInIframe } from "../util/iframe";
import React, { useEffect, useRef } from "react";
interface HtmlOutputProps {
diff --git a/src/components/outputs/shared-with-iframe/ImageOutput.tsx b/packages/shared/components/ImageOutput.tsx
similarity index 100%
rename from src/components/outputs/shared-with-iframe/ImageOutput.tsx
rename to packages/shared/components/ImageOutput.tsx
diff --git a/src/components/outputs/shared-with-iframe/JsonOutput.tsx b/packages/shared/components/JsonOutput.tsx
similarity index 100%
rename from src/components/outputs/shared-with-iframe/JsonOutput.tsx
rename to packages/shared/components/JsonOutput.tsx
diff --git a/src/components/outputs/shared-with-iframe/MarkdownRenderer.tsx b/packages/shared/components/MarkdownRenderer.tsx
similarity index 100%
rename from src/components/outputs/shared-with-iframe/MarkdownRenderer.tsx
rename to packages/shared/components/MarkdownRenderer.tsx
diff --git a/src/components/outputs/shared-with-iframe/PlainTextOutput.tsx b/packages/shared/components/PlainTextOutput.tsx
similarity index 100%
rename from src/components/outputs/shared-with-iframe/PlainTextOutput.tsx
rename to packages/shared/components/PlainTextOutput.tsx
diff --git a/src/components/outputs/shared-with-iframe/README.md b/packages/shared/components/README.md
similarity index 97%
rename from src/components/outputs/shared-with-iframe/README.md
rename to packages/shared/components/README.md
index b5d8dae1..a2403541 100644
--- a/src/components/outputs/shared-with-iframe/README.md
+++ b/packages/shared/components/README.md
@@ -6,7 +6,7 @@ Realistically, we can't put all shared code into this folder. We still depend on
🚨 IMPORTANT: do not depend on any LiveStore hooks in this folder like `useQuery`. Components in an iframe don't get access to React Context from the rest of the page.
-🚨 IMPORTANT: tailwind styles will not get picked up in the iframe build unless they're in the `shared-with-iframe` folder. See: `iframe-outputs/src/style.css`.
+🚨 IMPORTANT: tailwind styles will not get picked up in the iframe build unless they're in the `@anode/shared` package. See: `packages/iframe-outputs/src/style.css`.
# Thoughts for the future
diff --git a/src/components/outputs/shared-with-iframe/RichOutputContent.tsx b/packages/shared/components/RichOutputContent.tsx
similarity index 80%
rename from src/components/outputs/shared-with-iframe/RichOutputContent.tsx
rename to packages/shared/components/RichOutputContent.tsx
index 1e85cc63..3fefd250 100644
--- a/src/components/outputs/shared-with-iframe/RichOutputContent.tsx
+++ b/packages/shared/components/RichOutputContent.tsx
@@ -8,59 +8,56 @@ import {
AI_TOOL_RESULT_MIME_TYPE,
isAiToolCallData,
isAiToolResultData,
-} from "@/schema";
+} from "../schema";
import { SuspenseSpinner } from "./SuspenseSpinner";
// Dynamic imports for heavy components
const MarkdownRenderer = React.lazy(() =>
- import("@/components/outputs/shared-with-iframe/MarkdownRenderer").then(
- (m) => ({
- default: m.MarkdownRenderer,
- })
- )
+ import("./MarkdownRenderer").then((m) => ({
+ default: m.MarkdownRenderer,
+ }))
);
+
const JsonOutput = React.lazy(() =>
- import("@/components/outputs/shared-with-iframe/JsonOutput").then((m) => ({
+ import("./JsonOutput").then((m) => ({
default: m.JsonOutput,
}))
);
+
const HtmlOutput = React.lazy(() =>
- import("@/components/outputs/shared-with-iframe/HtmlOutput").then((m) => ({
+ import("./HtmlOutput").then((m) => ({
default: m.HtmlOutput,
}))
);
+
const ImageOutput = React.lazy(() =>
- import("@/components/outputs/shared-with-iframe/ImageOutput").then((m) => ({
+ import("./ImageOutput").then((m) => ({
default: m.ImageOutput,
}))
);
+
const SvgOutput = React.lazy(() =>
- import("@/components/outputs/shared-with-iframe/SvgOutput").then((m) => ({
+ import("./SvgOutput").then((m) => ({
default: m.SvgOutput,
}))
);
+
const PlainTextOutput = React.lazy(() =>
- import("@/components/outputs/shared-with-iframe/PlainTextOutput").then(
- (m) => ({
- default: m.PlainTextOutput,
- })
- )
+ import("./PlainTextOutput").then((m) => ({
+ default: m.PlainTextOutput,
+ }))
);
-// Dynamic imports for AI outputs
const AiToolCallOutput = React.lazy(() =>
- import("@/components/outputs/shared-with-iframe/AiToolCallOutput").then(
- (m) => ({
- default: m.AiToolCallOutput,
- })
- )
+ import("./AiToolCallOutput").then((m) => ({
+ default: m.AiToolCallOutput,
+ }))
);
+
const AiToolResultOutput = React.lazy(() =>
- import("@/components/outputs/shared-with-iframe/AiToolResultOutput").then(
- (m) => ({
- default: m.AiToolResultOutput,
- })
- )
+ import("./AiToolResultOutput").then((m) => ({
+ default: m.AiToolResultOutput,
+ }))
);
export function RichOutputContent({
diff --git a/src/components/outputs/shared-with-iframe/SingleOutput.tsx b/packages/shared/components/SingleOutput.tsx
similarity index 95%
rename from src/components/outputs/shared-with-iframe/SingleOutput.tsx
rename to packages/shared/components/SingleOutput.tsx
index bb7596f2..6dca6e77 100644
--- a/src/components/outputs/shared-with-iframe/SingleOutput.tsx
+++ b/packages/shared/components/SingleOutput.tsx
@@ -1,9 +1,6 @@
import React from "react";
-import {
- AnsiErrorOutput,
- AnsiStreamOutput,
-} from "@/components/outputs/shared-with-iframe/AnsiOutput";
+import { AnsiErrorOutput, AnsiStreamOutput } from "./AnsiOutput";
import {
AI_TOOL_CALL_MIME_TYPE,
AI_TOOL_RESULT_MIME_TYPE,
@@ -15,18 +12,16 @@ import {
TEXT_MIME_TYPES,
isArtifactContainer,
isInlineContainer,
-} from "@/schema";
+} from "../schema";
import PlainTextOutput from "./PlainTextOutput";
import { RichOutputContent } from "./RichOutputContent";
import { SuspenseSpinner } from "./SuspenseSpinner";
// Dynamic imports for heavy components
const MarkdownRenderer = React.lazy(() =>
- import("@/components/outputs/shared-with-iframe/MarkdownRenderer").then(
- (m) => ({
- default: m.MarkdownRenderer,
- })
- )
+ import("./MarkdownRenderer").then((m) => ({
+ default: m.MarkdownRenderer,
+ }))
);
/**
diff --git a/src/components/outputs/shared-with-iframe/SuspenseSpinner.tsx b/packages/shared/components/SuspenseSpinner.tsx
similarity index 92%
rename from src/components/outputs/shared-with-iframe/SuspenseSpinner.tsx
rename to packages/shared/components/SuspenseSpinner.tsx
index 9ab33787..c1f27271 100644
--- a/src/components/outputs/shared-with-iframe/SuspenseSpinner.tsx
+++ b/packages/shared/components/SuspenseSpinner.tsx
@@ -1,5 +1,5 @@
import { Suspense } from "react";
-import { Spinner, type SpinnerSize } from "../../ui/Spinner";
+import { Spinner, type SpinnerSize } from "../ui/Spinner";
import React from "react";
import { useTimeout } from "react-use";
diff --git a/src/components/outputs/shared-with-iframe/SvgOutput.tsx b/packages/shared/components/SvgOutput.tsx
similarity index 87%
rename from src/components/outputs/shared-with-iframe/SvgOutput.tsx
rename to packages/shared/components/SvgOutput.tsx
index a39466bd..9727a492 100644
--- a/src/components/outputs/shared-with-iframe/SvgOutput.tsx
+++ b/packages/shared/components/SvgOutput.tsx
@@ -1,4 +1,4 @@
-import { throwIfNotInIframe } from "@/util/iframe";
+import { throwIfNotInIframe } from "../util/iframe";
import React from "react";
interface SvgOutputProps {
diff --git a/src/components/outputs/shared-with-iframe/comms.ts b/packages/shared/components/comms.ts
similarity index 99%
rename from src/components/outputs/shared-with-iframe/comms.ts
rename to packages/shared/components/comms.ts
index f3388de6..ae8ee64c 100644
--- a/src/components/outputs/shared-with-iframe/comms.ts
+++ b/packages/shared/components/comms.ts
@@ -1,7 +1,7 @@
// NOTE: code here is shared between the iframe and the parent page.
// It's done to colocate types to ensure typesafety across the two bundles.
-import { OutputData } from "@/schema";
+import { OutputData } from "../schema";
import { useEffect, useRef, useState } from "react";
type UpdateOutputsEvent = {
diff --git a/packages/shared/index.ts b/packages/shared/index.ts
new file mode 100644
index 00000000..bf747fd1
--- /dev/null
+++ b/packages/shared/index.ts
@@ -0,0 +1,22 @@
+// Re-export all shared components
+export { AiToolApprovalOutput } from "./components/AiToolApprovalOutput";
+export { AiToolCallOutput } from "./components/AiToolCallOutput";
+export { AiToolResultOutput } from "./components/AiToolResultOutput";
+export {
+ AnsiOutput,
+ AnsiErrorOutput,
+ AnsiStreamOutput,
+} from "./components/AnsiOutput";
+export { HtmlOutput } from "./components/HtmlOutput";
+export { ImageOutput } from "./components/ImageOutput";
+export { JsonOutput } from "./components/JsonOutput";
+export { MarkdownRenderer } from "./components/MarkdownRenderer";
+export { PlainTextOutput } from "./components/PlainTextOutput";
+export { RichOutputContent } from "./components/RichOutputContent";
+export { SingleOutput } from "./components/SingleOutput";
+export { SuspenseSpinner } from "./components/SuspenseSpinner";
+export { SvgOutput } from "./components/SvgOutput";
+
+// Export comms utilities
+export * from "./components/comms";
+export { sendFromIframe } from "./components/comms";
diff --git a/packages/shared/lib/utils.ts b/packages/shared/lib/utils.ts
new file mode 100644
index 00000000..365058ce
--- /dev/null
+++ b/packages/shared/lib/utils.ts
@@ -0,0 +1,6 @@
+import { type ClassValue, clsx } from "clsx";
+import { twMerge } from "tailwind-merge";
+
+export function cn(...inputs: ClassValue[]) {
+ return twMerge(clsx(inputs));
+}
diff --git a/packages/shared/package.json b/packages/shared/package.json
new file mode 100644
index 00000000..571ce2e4
--- /dev/null
+++ b/packages/shared/package.json
@@ -0,0 +1,48 @@
+{
+ "name": "@anode/shared",
+ "version": "0.2.0",
+ "type": "module",
+ "private": true,
+ "description": "Shared components between Anode UI and iframe outputs",
+ "exports": {
+ ".": {
+ "types": "./dist/index.d.ts",
+ "default": "./dist/index.js"
+ },
+ "./components/*": {
+ "types": "./dist/components/*.d.ts",
+ "default": "./dist/components/*.js"
+ }
+ },
+ "scripts": {
+ "build": "tsc --build",
+ "dev": "tsc --build --watch",
+ "clean": "rm -rf dist",
+ "type-check": "tsc --noEmit"
+ },
+ "peerDependencies": {
+ "react": "19.0.0",
+ "react-dom": "19.0.0",
+ "@radix-ui/react-slot": "^1.2.3"
+ },
+ "dependencies": {
+ "@microlink/react-json-view": "^1.26.2",
+ "@runt/schema": "jsr:^0.13.0",
+ "ansi-to-react": "^6.1.6",
+ "class-variance-authority": "^0.7.1",
+ "clsx": "^2.1.1",
+ "lucide-react": "^0.514.0",
+ "react-markdown": "^10.1.0",
+ "react-syntax-highlighter": "^15.6.1",
+ "react-use": "^17.6.0",
+ "remark-gfm": "^4.0.1",
+ "strip-ansi": "^7.1.0",
+ "tailwind-merge": "^3.3.1"
+ },
+ "devDependencies": {
+ "@types/react": "^19.1.8",
+ "@types/react-dom": "^19.1.6",
+ "@types/react-syntax-highlighter": "^15.5.13",
+ "typescript": "^5.8.3"
+ }
+}
diff --git a/packages/shared/schema.ts b/packages/shared/schema.ts
new file mode 100644
index 00000000..05f9642a
--- /dev/null
+++ b/packages/shared/schema.ts
@@ -0,0 +1,2 @@
+// Re-export everything from the JSR schema package
+export * from "@runt/schema";
diff --git a/packages/shared/tsconfig.json b/packages/shared/tsconfig.json
new file mode 100644
index 00000000..02a95c43
--- /dev/null
+++ b/packages/shared/tsconfig.json
@@ -0,0 +1,32 @@
+{
+ "compilerOptions": {
+ "target": "ES2022",
+ "module": "ESNext",
+ "moduleResolution": "bundler",
+ "allowSyntheticDefaultImports": true,
+ "esModuleInterop": true,
+ "jsx": "react-jsx",
+ "declaration": true,
+ "declarationMap": true,
+ "outDir": "./dist",
+ "rootDir": "./",
+ "strict": true,
+ "skipLibCheck": true,
+ "forceConsistentCasingInFileNames": true,
+ "resolveJsonModule": true,
+ "isolatedModules": true,
+ "noEmit": false,
+ "incremental": true,
+ "composite": true,
+ "tsBuildInfoFile": "./dist/.tsbuildinfo"
+ },
+ "include": [
+ "components/**/*",
+ "ui/**/*",
+ "util/**/*",
+ "lib/**/*",
+ "*.ts",
+ "*.tsx"
+ ],
+ "exclude": ["node_modules", "dist", "**/*.test.*", "**/*.spec.*"]
+}
diff --git a/packages/shared/ui/Spinner.tsx b/packages/shared/ui/Spinner.tsx
new file mode 100644
index 00000000..65963e49
--- /dev/null
+++ b/packages/shared/ui/Spinner.tsx
@@ -0,0 +1,19 @@
+import { cn } from "../lib/utils";
+import { LoaderIcon, type LucideProps } from "lucide-react";
+
+export type SpinnerSize = "sm" | "md" | "lg";
+
+type SpinnerProps = LucideProps & {
+ size?: SpinnerSize;
+};
+
+export const Spinner = ({ className, size = "sm", ...props }: SpinnerProps) => (
+
+);
diff --git a/packages/shared/ui/button.tsx b/packages/shared/ui/button.tsx
new file mode 100644
index 00000000..36af8ee9
--- /dev/null
+++ b/packages/shared/ui/button.tsx
@@ -0,0 +1,60 @@
+import * as React from "react";
+import { Slot } from "@radix-ui/react-slot";
+import { cva, type VariantProps } from "class-variance-authority";
+
+import { cn } from "../lib/utils";
+
+const buttonVariants = cva(
+ "inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-md text-sm font-medium transition-all disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg:not([class*='size-'])]:size-4 shrink-0 [&_svg]:shrink-0 outline-none focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:ring-[3px] aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive",
+ {
+ variants: {
+ variant: {
+ default:
+ "bg-primary text-primary-foreground shadow-xs hover:bg-primary/90",
+ destructive:
+ "bg-destructive text-white shadow-xs hover:bg-destructive/90 focus-visible:ring-destructive/20 dark:focus-visible:ring-destructive/40 dark:bg-destructive/60",
+ outline:
+ "border bg-background shadow-xs hover:bg-accent hover:text-accent-foreground dark:bg-input/30 dark:border-input dark:hover:bg-input/50",
+ secondary:
+ "bg-secondary text-secondary-foreground shadow-xs hover:bg-secondary/80",
+ ghost:
+ "hover:bg-accent hover:text-accent-foreground dark:hover:bg-accent/50",
+ link: "text-primary underline-offset-4 hover:underline",
+ },
+ size: {
+ default: "h-9 px-4 py-2 has-[>svg]:px-3",
+ xs: "h-6 px-2 has-[>svg]:px-1.5",
+ sm: "h-8 rounded-md gap-1.5 px-3 has-[>svg]:px-2.5",
+ lg: "h-10 rounded-md px-6 has-[>svg]:px-4",
+ icon: "size-9",
+ },
+ },
+ defaultVariants: {
+ variant: "default",
+ size: "default",
+ },
+ }
+);
+
+function Button({
+ className,
+ variant,
+ size,
+ asChild = false,
+ ...props
+}: React.ComponentProps<"button"> &
+ VariantProps & {
+ asChild?: boolean;
+ }) {
+ const Comp = asChild ? Slot : "button";
+
+ return (
+
+ );
+}
+
+export { Button, buttonVariants };
diff --git a/packages/shared/ui/card.tsx b/packages/shared/ui/card.tsx
new file mode 100644
index 00000000..4c76303c
--- /dev/null
+++ b/packages/shared/ui/card.tsx
@@ -0,0 +1,92 @@
+import * as React from "react";
+
+import { cn } from "../lib/utils";
+
+function Card({ className, ...props }: React.ComponentProps<"div">) {
+ return (
+
+ );
+}
+
+function CardHeader({ className, ...props }: React.ComponentProps<"div">) {
+ return (
+
+ );
+}
+
+function CardTitle({ className, ...props }: React.ComponentProps<"div">) {
+ return (
+
+ );
+}
+
+function CardDescription({ className, ...props }: React.ComponentProps<"div">) {
+ return (
+
+ );
+}
+
+function CardAction({ className, ...props }: React.ComponentProps<"div">) {
+ return (
+
+ );
+}
+
+function CardContent({ className, ...props }: React.ComponentProps<"div">) {
+ return (
+
+ );
+}
+
+function CardFooter({ className, ...props }: React.ComponentProps<"div">) {
+ return (
+
+ );
+}
+
+export {
+ Card,
+ CardAction,
+ CardContent,
+ CardDescription,
+ CardFooter,
+ CardHeader,
+ CardTitle,
+};
diff --git a/packages/shared/util/iframe.ts b/packages/shared/util/iframe.ts
new file mode 100644
index 00000000..d222f0ff
--- /dev/null
+++ b/packages/shared/util/iframe.ts
@@ -0,0 +1,9 @@
+function throwIfNotInIframe() {
+ if (window.self === window.top) {
+ throw new Error(
+ "This content must be rendered inside an iframe for security reasons."
+ );
+ }
+}
+
+export { throwIfNotInIframe };
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index a119cb9b..cf70acf4 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -19,6 +19,9 @@ importers:
.:
dependencies:
+ '@anode/shared':
+ specifier: workspace:*
+ version: link:packages/shared
'@codemirror/autocomplete':
specifier: ^6.18.6
version: 6.18.6
@@ -354,6 +357,116 @@ importers:
specifier: 4.27.0
version: 4.27.0(@cloudflare/workers-types@4.20250813.0)
+ packages/iframe-outputs:
+ dependencies:
+ '@anode/shared':
+ specifier: workspace:*
+ version: link:../shared
+ modern-normalize:
+ specifier: ^3.0.1
+ version: 3.0.1
+ react:
+ specifier: 19.0.0
+ version: 19.0.0
+ react-dom:
+ specifier: 19.0.0
+ version: 19.0.0(react@19.0.0)
+ tw-animate-css:
+ specifier: ^1.3.4
+ version: 1.3.5
+ devDependencies:
+ '@cloudflare/workers-types':
+ specifier: ^4.20250813.0
+ version: 4.20250813.0
+ '@tailwindcss/typography':
+ specifier: ^0.5.16
+ version: 0.5.16(tailwindcss@4.1.11)
+ '@tailwindcss/vite':
+ specifier: ^4.1.10
+ version: 4.1.11(vite@6.3.5(@types/node@24.0.13)(jiti@2.4.2)(lightningcss@1.30.1)(yaml@2.8.1))
+ '@types/react':
+ specifier: ^19.1.8
+ version: 19.1.8
+ '@types/react-dom':
+ specifier: ^19.1.6
+ version: 19.1.6(@types/react@19.1.8)
+ '@vitejs/plugin-react':
+ specifier: ^4.5.2
+ version: 4.6.0(vite@6.3.5(@types/node@24.0.13)(jiti@2.4.2)(lightningcss@1.30.1)(yaml@2.8.1))
+ tailwindcss:
+ specifier: ^4.1.10
+ version: 4.1.11
+ typescript:
+ specifier: ^5.8.3
+ version: 5.8.3
+ vite:
+ specifier: ^6.3.5
+ version: 6.3.5(@types/node@24.0.13)(jiti@2.4.2)(lightningcss@1.30.1)(yaml@2.8.1)
+ wrangler:
+ specifier: 4.27.0
+ version: 4.27.0(@cloudflare/workers-types@4.20250813.0)
+
+ packages/shared:
+ dependencies:
+ '@microlink/react-json-view':
+ specifier: ^1.26.2
+ version: 1.26.2(@types/react@19.1.8)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)
+ '@radix-ui/react-slot':
+ specifier: ^1.2.3
+ version: 1.2.3(@types/react@19.1.8)(react@19.0.0)
+ '@runt/schema':
+ specifier: jsr:^0.13.0
+ version: '@jsr/runt__schema@0.13.0(f9c23af240f2640c0a9abef8711d3cc6)'
+ ansi-to-react:
+ specifier: ^6.1.6
+ version: 6.1.6(react-dom@19.0.0(react@19.0.0))(react@19.0.0)
+ class-variance-authority:
+ specifier: ^0.7.1
+ version: 0.7.1
+ clsx:
+ specifier: ^2.1.1
+ version: 2.1.1
+ lucide-react:
+ specifier: ^0.514.0
+ version: 0.514.0(react@19.0.0)
+ react:
+ specifier: 19.0.0
+ version: 19.0.0
+ react-dom:
+ specifier: 19.0.0
+ version: 19.0.0(react@19.0.0)
+ react-markdown:
+ specifier: ^10.1.0
+ version: 10.1.0(@types/react@19.1.8)(react@19.0.0)
+ react-syntax-highlighter:
+ specifier: ^15.6.1
+ version: 15.6.1(react@19.0.0)
+ react-use:
+ specifier: ^17.6.0
+ version: 17.6.0(react-dom@19.0.0(react@19.0.0))(react@19.0.0)
+ remark-gfm:
+ specifier: ^4.0.1
+ version: 4.0.1
+ strip-ansi:
+ specifier: ^7.1.0
+ version: 7.1.0
+ tailwind-merge:
+ specifier: ^3.3.1
+ version: 3.3.1
+ devDependencies:
+ '@types/react':
+ specifier: ^19.1.8
+ version: 19.1.8
+ '@types/react-dom':
+ specifier: ^19.1.6
+ version: 19.1.6(@types/react@19.1.8)
+ '@types/react-syntax-highlighter':
+ specifier: ^15.5.13
+ version: 15.5.13
+ typescript:
+ specifier: ^5.8.3
+ version: 5.8.3
+
packages:
'@adobe/css-tools@4.4.3':
diff --git a/pnpm-workspace.yaml b/pnpm-workspace.yaml
new file mode 100644
index 00000000..dee51e92
--- /dev/null
+++ b/pnpm-workspace.yaml
@@ -0,0 +1,2 @@
+packages:
+ - "packages/*"
diff --git a/scripts/deploy-iframe-outputs.sh b/scripts/deploy-iframe-outputs.sh
index 928fb868..9b0dc00c 100755
--- a/scripts/deploy-iframe-outputs.sh
+++ b/scripts/deploy-iframe-outputs.sh
@@ -6,7 +6,7 @@ set -euo pipefail
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
PROJECT_ROOT="$(cd "$SCRIPT_DIR/.." && pwd)"
-IFRAME_DIR="$PROJECT_ROOT/iframe-outputs"
+IFRAME_DIR="$PROJECT_ROOT/packages/iframe-outputs"
# Colors for output
RED='\033[0;31m'
@@ -23,8 +23,8 @@ echo "Directory: $IFRAME_DIR"
echo ""
# Check if we're in the right place
-if [ ! -f "$IFRAME_DIR/wrangler.toml" ]; then
- echo -e "${RED}❌ Error: Cannot find iframe-outputs/wrangler.toml${NC}"
+if [ ! -f "$IFRAME_DIR/worker/wrangler.toml" ]; then
+ echo -e "${RED}❌ Error: Cannot find packages/iframe-outputs/worker/wrangler.toml${NC}"
echo "Please run this script from the anode project root"
exit 1
fi
@@ -36,8 +36,8 @@ if ! command -v wrangler &> /dev/null; then
exit 1
fi
-# Change to iframe directory
-cd "$IFRAME_DIR"
+# Change to iframe worker directory
+cd "$IFRAME_DIR/worker"
# Validate environment
case "$ENV" in
@@ -84,7 +84,7 @@ if [ $? -eq 0 ]; then
echo " VITE_IFRAME_OUTPUT_URI should point to the deployed domain"
echo ""
echo "3. Monitor logs with:"
- echo " cd iframe-outputs && pnpm logs${ENV:+:$ENV}"
+ echo " cd packages/iframe-outputs/worker && pnpm logs${ENV:+:$ENV}"
else
echo -e "${RED}❌ Deployment failed${NC}"
exit 1
diff --git a/src/components/notebook/cell/ExecutableCell.tsx b/src/components/notebook/cell/ExecutableCell.tsx
index 345eb575..0c17cbe7 100644
--- a/src/components/notebook/cell/ExecutableCell.tsx
+++ b/src/components/notebook/cell/ExecutableCell.tsx
@@ -36,7 +36,7 @@ import { SqlToolbar } from "./toolbars/SqlToolbar.js";
import { MaybeCellOutputs } from "@/components/outputs/MaybeCellOutputs.js";
import { useToolApprovals } from "@/hooks/useToolApprovals.js";
-import { AiToolApprovalOutput } from "../../outputs/shared-with-iframe/AiToolApprovalOutput.js";
+import { AiToolApprovalOutput } from "@anode/shared";
import { cn } from "@/lib/utils.js";
// Cell-specific styling configuration
diff --git a/src/components/notebook/cell/MarkdownCell.tsx b/src/components/notebook/cell/MarkdownCell.tsx
index 482767c5..836a8ad5 100644
--- a/src/components/notebook/cell/MarkdownCell.tsx
+++ b/src/components/notebook/cell/MarkdownCell.tsx
@@ -36,11 +36,9 @@ interface MarkdownCellProps {
}
const MarkdownRenderer = React.lazy(() =>
- import("@/components/outputs/shared-with-iframe/MarkdownRenderer.js").then(
- (m) => ({
- default: m.MarkdownRenderer,
- })
- )
+ import("@anode/shared").then((m) => ({
+ default: m.MarkdownRenderer,
+ }))
);
export const MarkdownCell: React.FC = ({
diff --git a/src/components/outputs/MaybeCellOutputs.tsx b/src/components/outputs/MaybeCellOutputs.tsx
index 1ca6a9c0..c0bc6d73 100644
--- a/src/components/outputs/MaybeCellOutputs.tsx
+++ b/src/components/outputs/MaybeCellOutputs.tsx
@@ -2,8 +2,7 @@ import { OutputData } from "@/schema";
import { groupConsecutiveStreamOutputs } from "@/util/output-grouping";
import { useQuery } from "@livestore/react";
import { useMemo, useState } from "react";
-import { SingleOutput } from "./shared-with-iframe/SingleOutput";
-import { useIframeCommsParent } from "./shared-with-iframe/comms";
+import { SingleOutput, useIframeCommsParent } from "@anode/shared";
import { outputsDeltasQuery, processDeltas } from "@/queries/outputDeltas";
import { cn } from "@/lib/utils";
import { useDebounce } from "react-use";
diff --git a/src/components/outputs/index.ts b/src/components/outputs/index.ts
index 5d7f463c..7ef854f5 100644
--- a/src/components/outputs/index.ts
+++ b/src/components/outputs/index.ts
@@ -1,23 +1,18 @@
-// Re-export AnsiOutput from the notebook folder for convenience
+// Re-export components from the shared package for convenience
import { AiToolCallData, AiToolResultData } from "@/schema";
-export { AiToolCallOutput } from "./shared-with-iframe/AiToolCallOutput.js";
-export { AiToolResultOutput } from "./shared-with-iframe/AiToolResultOutput.js";
-export { AiToolApprovalOutput } from "./shared-with-iframe/AiToolApprovalOutput.js";
-export { HtmlOutput } from "./shared-with-iframe/HtmlOutput.js";
-export { ImageOutput } from "./shared-with-iframe/ImageOutput.js";
-export { JsonOutput } from "./shared-with-iframe/JsonOutput.js";
-
-export { PlainTextOutput } from "./shared-with-iframe/PlainTextOutput.js";
-export { SingleOutput as RichOutput } from "./shared-with-iframe/SingleOutput.js";
-export { SvgOutput } from "./shared-with-iframe/SvgOutput.js";
+export { AiToolCallOutput } from "@anode/shared";
+export { AiToolResultOutput } from "@anode/shared";
+export { AiToolApprovalOutput } from "@anode/shared";
+export { HtmlOutput } from "@anode/shared";
+export { ImageOutput } from "@anode/shared";
+export { JsonOutput } from "@anode/shared";
+export { PlainTextOutput } from "@anode/shared";
+export { SingleOutput as RichOutput } from "@anode/shared";
+export { SvgOutput } from "@anode/shared";
// Note: Heavy output components are now dynamically imported in RichOutput.tsx
-// to reduce bundle size. They are no longer exported from this index file.
-
-// Re-export types from schema for consistency
-export type { OutputData, AiToolCallData, AiToolResultData } from "@/schema";
+// from the shared package
-// Legacy type aliases for backward compatibility
-export type ToolCallData = AiToolCallData;
-export type ToolResultData = AiToolResultData;
+// Export types for convenience
+export type { AiToolCallData, AiToolResultData };
diff --git a/src/util/prefetch.ts b/src/util/prefetch.ts
index 36d29293..39c47445 100644
--- a/src/util/prefetch.ts
+++ b/src/util/prefetch.ts
@@ -73,34 +73,11 @@ export function prefetchOutputChunks(): void {
// Preload react-spring first as it's used on initial page load
import("@react-spring/web").catch(() => {});
- // These imports will trigger chunk loading but won't execute the modules
- // until they're actually needed via React.lazy()
- import(
- "../components/outputs/shared-with-iframe/MarkdownRenderer.js"
- ).catch(() => {
+ // This import will trigger chunk loading for all shared components
+ // but won't execute the modules until they're actually needed via React.lazy()
+ import("@anode/shared").catch(() => {
// Silently ignore prefetch failures
});
- import("../components/outputs/shared-with-iframe/JsonOutput.js").catch(
- () => {}
- );
- import("../components/outputs/shared-with-iframe/PlainTextOutput.js").catch(
- () => {}
- );
- import("../components/outputs/shared-with-iframe/HtmlOutput.js").catch(
- () => {}
- );
- import("../components/outputs/shared-with-iframe/ImageOutput.js").catch(
- () => {}
- );
- import("../components/outputs/shared-with-iframe/SvgOutput.js").catch(
- () => {}
- );
- import(
- "../components/outputs/shared-with-iframe/AiToolCallOutput.js"
- ).catch(() => {});
- import(
- "../components/outputs/shared-with-iframe/AiToolResultOutput.js"
- ).catch(() => {});
});
}
@@ -136,13 +113,8 @@ export function prefetchOutputsAggressive(): void {
export function prefetchOutputsConservative(): void {
prefetchWhenIdle(
() => {
- // Only prefetch the most commonly used components
- import(
- "../components/outputs/shared-with-iframe/PlainTextOutput.js"
- ).catch(() => {});
- import(
- "../components/outputs/shared-with-iframe/MarkdownRenderer.js"
- ).catch(() => {});
+ // Prefetch shared components package
+ import("@anode/shared").catch(() => {});
// Preload react-spring as it's used in the loading screen
import("@react-spring/web").catch(() => {});
},
diff --git a/test/components/outputs/AiToolResultOutput.test.tsx b/test/components/outputs/AiToolResultOutput.test.tsx
index 1770a575..8aeadd81 100644
--- a/test/components/outputs/AiToolResultOutput.test.tsx
+++ b/test/components/outputs/AiToolResultOutput.test.tsx
@@ -2,7 +2,7 @@ import React from "react";
import { render, screen } from "@testing-library/react";
import { describe, it, expect } from "vitest";
import type { AiToolResultData } from "@runt/schema";
-import { AiToolResultOutput } from "../../../src/components/outputs/shared-with-iframe/AiToolResultOutput";
+import { AiToolResultOutput } from "@anode/shared";
describe("AiToolResultOutput", () => {
it("renders success result correctly", () => {
diff --git a/tsconfig.json b/tsconfig.json
index 78bacea3..14912904 100644
--- a/tsconfig.json
+++ b/tsconfig.json
@@ -14,17 +14,22 @@
"jsx": "react-jsx",
"baseUrl": ".",
"paths": {
- "@/*": ["./src/*"]
+ "@/*": ["./src/*"],
+ "@anode/shared": ["./packages/shared/index.ts"],
+ "@anode/shared/*": ["./packages/shared/*"]
},
"strict": true,
"noUnusedLocals": true,
"noUnusedParameters": true,
"noFallthroughCasesInSwitch": true
},
- "include": ["src", "src/types", "backend", "iframe-outputs/src"],
+ "include": ["src", "src/types", "backend"],
"references": [
{
"path": "./tsconfig.node.json"
+ },
+ {
+ "path": "./packages/shared"
}
]
}
diff --git a/tsconfig.node.json b/tsconfig.node.json
index 680fd0be..1c5d0d97 100644
--- a/tsconfig.node.json
+++ b/tsconfig.node.json
@@ -10,6 +10,6 @@
"include": [
"vite.config.ts",
"vite-plugins/**/*.ts",
- "iframe-outputs/vite.config.ts"
+ "packages/*/vite.config.ts"
]
}
diff --git a/vitest.config.ts b/vitest.config.ts
index f2f250b8..099fe4bb 100644
--- a/vitest.config.ts
+++ b/vitest.config.ts
@@ -74,6 +74,7 @@ export default defineConfig({
alias: {
"@": path.resolve(__dirname, "./src"),
backend: path.resolve(__dirname, "./backend"),
+ "@anode/shared": path.resolve(__dirname, "./packages/shared"),
"@anode/web-client": path.resolve(__dirname, "./packages/web-client/src"),
"@anode/docworker": path.resolve(__dirname, "./packages/docworker/src"),
"@anode/pyodide-runtime-agent": path.resolve(