From f69034776cdabd93a4cd6a56f4caae499460da6c Mon Sep 17 00:00:00 2001 From: Kyle Kelley Date: Mon, 8 Sep 2025 07:15:12 -0700 Subject: [PATCH] starter workspace --- eslint.config.js | 9 +- iframe-outputs/src/tsconfig.node.json | 10 - iframe-outputs/worker/package.json | 33 - iframe-outputs/worker/pnpm-lock.yaml | 920 ------------------ package.json | 25 +- .../iframe-outputs}/README.md | 0 packages/iframe-outputs/package.json | 53 + .../src/components/IframeReactApp.tsx | 3 +- .../iframe-outputs}/src/react-main.tsx | 2 +- .../iframe-outputs}/src/react.html | 0 .../iframe-outputs}/src/style.css | 4 +- packages/iframe-outputs/tailwind.config.js | 65 ++ .../iframe-outputs}/test-iframe.html | 0 packages/iframe-outputs/tsconfig.json | 39 + .../iframe-outputs}/vite.config.ts | 12 +- .../iframe-outputs}/worker/tsconfig.json | 0 .../iframe-outputs}/worker/worker.ts | 0 .../iframe-outputs}/worker/wrangler.toml | 0 .../components}/AiToolApprovalOutput.tsx | 4 +- .../shared/components}/AiToolCallOutput.tsx | 2 +- .../shared/components}/AiToolResultOutput.tsx | 2 +- .../shared/components}/AnsiOutput.tsx | 0 .../shared/components}/HtmlOutput.tsx | 2 +- .../shared/components}/ImageOutput.tsx | 0 .../shared/components}/JsonOutput.tsx | 0 .../shared/components}/MarkdownRenderer.tsx | 0 .../shared/components}/PlainTextOutput.tsx | 0 .../shared/components}/README.md | 2 +- .../shared/components}/RichOutputContent.tsx | 49 +- .../shared/components}/SingleOutput.tsx | 15 +- .../shared/components}/SuspenseSpinner.tsx | 2 +- .../shared/components}/SvgOutput.tsx | 2 +- .../shared/components}/comms.ts | 2 +- packages/shared/index.ts | 22 + packages/shared/lib/utils.ts | 6 + packages/shared/package.json | 48 + packages/shared/schema.ts | 2 + packages/shared/tsconfig.json | 32 + packages/shared/ui/Spinner.tsx | 19 + packages/shared/ui/button.tsx | 60 ++ packages/shared/ui/card.tsx | 92 ++ packages/shared/util/iframe.ts | 9 + pnpm-lock.yaml | 113 +++ pnpm-workspace.yaml | 2 + scripts/deploy-iframe-outputs.sh | 12 +- .../notebook/cell/ExecutableCell.tsx | 2 +- src/components/notebook/cell/MarkdownCell.tsx | 8 +- src/components/outputs/MaybeCellOutputs.tsx | 3 +- src/components/outputs/index.ts | 31 +- src/util/prefetch.ts | 38 +- .../outputs/AiToolResultOutput.test.tsx | 2 +- tsconfig.json | 9 +- tsconfig.node.json | 2 +- vitest.config.ts | 1 + 54 files changed, 667 insertions(+), 1103 deletions(-) delete mode 100644 iframe-outputs/src/tsconfig.node.json delete mode 100644 iframe-outputs/worker/package.json delete mode 100644 iframe-outputs/worker/pnpm-lock.yaml rename {iframe-outputs => packages/iframe-outputs}/README.md (100%) create mode 100644 packages/iframe-outputs/package.json rename {iframe-outputs => packages/iframe-outputs}/src/components/IframeReactApp.tsx (64%) rename {iframe-outputs => packages/iframe-outputs}/src/react-main.tsx (89%) rename {iframe-outputs => packages/iframe-outputs}/src/react.html (100%) rename {iframe-outputs => packages/iframe-outputs}/src/style.css (97%) create mode 100644 packages/iframe-outputs/tailwind.config.js rename {iframe-outputs => packages/iframe-outputs}/test-iframe.html (100%) create mode 100644 packages/iframe-outputs/tsconfig.json rename {iframe-outputs => packages/iframe-outputs}/vite.config.ts (66%) rename {iframe-outputs => packages/iframe-outputs}/worker/tsconfig.json (100%) rename {iframe-outputs => packages/iframe-outputs}/worker/worker.ts (100%) rename {iframe-outputs => packages/iframe-outputs}/worker/wrangler.toml (100%) rename {src/components/outputs/shared-with-iframe => packages/shared/components}/AiToolApprovalOutput.tsx (98%) rename {src/components/outputs/shared-with-iframe => packages/shared/components}/AiToolCallOutput.tsx (98%) rename {src/components/outputs/shared-with-iframe => packages/shared/components}/AiToolResultOutput.tsx (96%) rename {src/components/outputs/shared-with-iframe => packages/shared/components}/AnsiOutput.tsx (100%) rename {src/components/outputs/shared-with-iframe => packages/shared/components}/HtmlOutput.tsx (93%) rename {src/components/outputs/shared-with-iframe => packages/shared/components}/ImageOutput.tsx (100%) rename {src/components/outputs/shared-with-iframe => packages/shared/components}/JsonOutput.tsx (100%) rename {src/components/outputs/shared-with-iframe => packages/shared/components}/MarkdownRenderer.tsx (100%) rename {src/components/outputs/shared-with-iframe => packages/shared/components}/PlainTextOutput.tsx (100%) rename {src/components/outputs/shared-with-iframe => packages/shared/components}/README.md (97%) rename {src/components/outputs/shared-with-iframe => packages/shared/components}/RichOutputContent.tsx (80%) rename {src/components/outputs/shared-with-iframe => packages/shared/components}/SingleOutput.tsx (95%) rename {src/components/outputs/shared-with-iframe => packages/shared/components}/SuspenseSpinner.tsx (92%) rename {src/components/outputs/shared-with-iframe => packages/shared/components}/SvgOutput.tsx (87%) rename {src/components/outputs/shared-with-iframe => packages/shared/components}/comms.ts (99%) create mode 100644 packages/shared/index.ts create mode 100644 packages/shared/lib/utils.ts create mode 100644 packages/shared/package.json create mode 100644 packages/shared/schema.ts create mode 100644 packages/shared/tsconfig.json create mode 100644 packages/shared/ui/Spinner.tsx create mode 100644 packages/shared/ui/button.tsx create mode 100644 packages/shared/ui/card.tsx create mode 100644 packages/shared/util/iframe.ts create mode 100644 pnpm-workspace.yaml 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(