diff options
| -rw-r--r-- | .gitignore | 2 | ||||
| -rw-r--r-- | apps/memory-graph-playground/src/app/page.tsx | 76 | ||||
| -rw-r--r-- | bun.lock | 462 | ||||
| -rw-r--r-- | package.json | 4 | ||||
| -rw-r--r-- | packages/memory-graph/CHANGELOG.md | 103 | ||||
| -rw-r--r-- | packages/memory-graph/package.json | 1 | ||||
| -rw-r--r-- | packages/memory-graph/src/components/graph-canvas.tsx | 515 | ||||
| -rw-r--r-- | packages/memory-graph/src/components/legend.css.ts | 118 | ||||
| -rw-r--r-- | packages/memory-graph/src/components/memory-graph.tsx | 313 | ||||
| -rw-r--r-- | packages/memory-graph/src/components/node-popover.css.ts | 176 | ||||
| -rw-r--r-- | packages/memory-graph/src/components/node-popover.tsx | 280 | ||||
| -rw-r--r-- | packages/memory-graph/src/constants.ts | 62 | ||||
| -rw-r--r-- | packages/memory-graph/src/hooks/use-force-simulation.ts | 180 | ||||
| -rw-r--r-- | packages/memory-graph/src/hooks/use-graph-data.ts | 431 | ||||
| -rw-r--r-- | packages/memory-graph/src/hooks/use-graph-interactions.ts | 34 | ||||
| -rw-r--r-- | packages/memory-graph/src/types.ts | 24 | ||||
| -rw-r--r-- | packages/memory-graph/src/utils/document-icons.ts | 237 |
17 files changed, 2304 insertions, 714 deletions
@@ -40,6 +40,6 @@ yarn-error.log* # Misc .DS_Store *.pem - +.claude .venv __pycache__ diff --git a/apps/memory-graph-playground/src/app/page.tsx b/apps/memory-graph-playground/src/app/page.tsx index 7192c4c2..581557b6 100644 --- a/apps/memory-graph-playground/src/app/page.tsx +++ b/apps/memory-graph-playground/src/app/page.tsx @@ -29,6 +29,10 @@ export default function Home() { // State for controlled space selection const [selectedSpace, setSelectedSpace] = useState<string>("all") + // State for slideshow + const [isSlideshowActive, setIsSlideshowActive] = useState(false) + const [currentSlideshowNode, setCurrentSlideshowNode] = useState<string | null>(null) + const PAGE_SIZE = 500 const fetchDocuments = useCallback( @@ -109,6 +113,23 @@ export default function Home() { setSelectedSpace("all") } + // Toggle slideshow + const handleToggleSlideshow = () => { + setIsSlideshowActive((prev) => !prev) + } + + // Handle slideshow node change + const handleSlideshowNodeChange = useCallback((nodeId: string | null) => { + // Track which node is being shown in slideshow + setCurrentSlideshowNode(nodeId) + console.log("Slideshow showing node:", nodeId) + }, []) + + // Handle slideshow stop (when user clicks outside) + const handleSlideshowStop = useCallback(() => { + setIsSlideshowActive(false) + }, []) + return ( <div className="flex flex-col h-screen bg-zinc-950"> {/* Header */} @@ -158,12 +179,49 @@ export default function Home() { </span> </div> </div> - <button - onClick={handleReset} - className="rounded-lg border border-zinc-700 px-3 py-1 text-xs font-medium text-zinc-300 transition-colors hover:bg-zinc-800" - > - Reset Filters - </button> + <div className="flex items-center gap-3"> + <button + onClick={handleToggleSlideshow} + className={`rounded-lg px-3 py-1.5 text-xs font-medium transition-colors flex items-center gap-1.5 ${ + isSlideshowActive + ? "bg-blue-600 text-white hover:bg-blue-700" + : "border border-zinc-700 text-zinc-300 hover:bg-zinc-800" + }`} + > + {isSlideshowActive ? ( + <> + <svg + width="12" + height="12" + viewBox="0 0 24 24" + fill="currentColor" + > + <rect x="6" y="6" width="12" height="12" /> + </svg> + Slideshow + </> + ) : ( + <> + <svg + width="12" + height="12" + viewBox="0 0 24 24" + fill="currentColor" + > + <path d="M8 5v14l11-7z" /> + </svg> + Slideshow + </> + )} + </button> + <div className="h-6 w-px bg-zinc-700" /> + <button + onClick={handleReset} + className="rounded-lg border border-zinc-700 px-3 py-1.5 text-xs font-medium text-zinc-300 transition-colors hover:bg-zinc-800" + > + Reset Filters + </button> + </div> </div> </div> )} @@ -225,6 +283,12 @@ export default function Home() { // Controlled space selection selectedSpace={selectedSpace} onSpaceChange={handleSpaceChange} + // Node limit - prevents performance issues with large graphs + maxNodes={500} + // Slideshow control + isSlideshowActive={isSlideshowActive} + onSlideshowNodeChange={handleSlideshowNodeChange} + onSlideshowStop={handleSlideshowStop} > <div className="flex h-full items-center justify-center"> <p className="text-zinc-400"> @@ -16,7 +16,7 @@ "@scalar/hono-api-reference": "^0.9.11", "@vanilla-extract/recipes": "^0.5.7", "ai": "^5.0.59", - "alchemy": "^0.55.2", + "alchemy": "^0.81.4", "atmn": "^0.0.16", "better-auth": "^1.3.3", "boxen": "^8.0.1", @@ -46,7 +46,7 @@ "drizzle-kit": "^0.31.4", "turbo": "^2.5.4", "typescript": "5.8.3", - "wrangler": "4.22.0", + "wrangler": "^4.42.2", }, }, "apps/browser-extension": { @@ -227,9 +227,11 @@ "@emotion/is-prop-valid": "^1.4.0", "@radix-ui/react-collapsible": "^1.1.12", "@radix-ui/react-slot": "^1.2.4", + "@supermemory/memory-graph": "^0.1.7", "@vanilla-extract/css": "^1.17.4", "@vanilla-extract/recipes": "^0.5.7", "@vanilla-extract/sprinkles": "^1.6.5", + "d3-force": "^3.0.0", "lucide-react": "^0.552.0", "motion": "^12.23.24", }, @@ -248,7 +250,7 @@ }, "packages/tools": { "name": "@supermemory/tools", - "version": "1.3.62", + "version": "1.3.60", "dependencies": { "@ai-sdk/anthropic": "^2.0.25", "@ai-sdk/openai": "^2.0.23", @@ -402,24 +404,12 @@ "@aws-sdk/client-dynamodb": ["@aws-sdk/[email protected]", "", { "dependencies": { "@aws-crypto/sha256-browser": "5.2.0", "@aws-crypto/sha256-js": "5.2.0", "@aws-sdk/core": "3.946.0", "@aws-sdk/credential-provider-node": "3.946.0", "@aws-sdk/dynamodb-codec": "3.946.0", "@aws-sdk/middleware-endpoint-discovery": "3.936.0", "@aws-sdk/middleware-host-header": "3.936.0", "@aws-sdk/middleware-logger": "3.936.0", "@aws-sdk/middleware-recursion-detection": "3.936.0", "@aws-sdk/middleware-user-agent": "3.946.0", "@aws-sdk/region-config-resolver": "3.936.0", "@aws-sdk/types": "3.936.0", "@aws-sdk/util-endpoints": "3.936.0", "@aws-sdk/util-user-agent-browser": "3.936.0", "@aws-sdk/util-user-agent-node": "3.946.0", "@smithy/config-resolver": "^4.4.3", "@smithy/core": "^3.18.7", "@smithy/fetch-http-handler": "^5.3.6", "@smithy/hash-node": "^4.2.5", "@smithy/invalid-dependency": "^4.2.5", "@smithy/middleware-content-length": "^4.2.5", "@smithy/middleware-endpoint": "^4.3.14", "@smithy/middleware-retry": "^4.4.14", "@smithy/middleware-serde": "^4.2.6", "@smithy/middleware-stack": "^4.2.5", "@smithy/node-config-provider": "^4.3.5", "@smithy/node-http-handler": "^4.4.5", "@smithy/protocol-http": "^5.3.5", "@smithy/smithy-client": "^4.9.10", "@smithy/types": "^4.9.0", "@smithy/url-parser": "^4.2.5", "@smithy/util-base64": "^4.3.0", "@smithy/util-body-length-browser": "^4.2.0", "@smithy/util-body-length-node": "^4.2.1", "@smithy/util-defaults-mode-browser": "^4.3.13", "@smithy/util-defaults-mode-node": "^4.2.16", "@smithy/util-endpoints": "^3.2.5", "@smithy/util-middleware": "^4.2.5", "@smithy/util-retry": "^4.2.5", "@smithy/util-utf8": "^4.2.0", "@smithy/util-waiter": "^4.2.5", "tslib": "^2.6.2" } }, "sha512-sMmJRa2Y+jQ+qMzx7V3SBKsTSQzLBvSuVbMNM/YGSZkr849a4a6Frl4U8HfFj4O+o71dvQ6h5PP6vlc/fW672g=="], - "@aws-sdk/client-ec2": ["@aws-sdk/[email protected]", "", { "dependencies": { "@aws-crypto/sha256-browser": "5.2.0", "@aws-crypto/sha256-js": "5.2.0", "@aws-sdk/core": "3.946.0", "@aws-sdk/credential-provider-node": "3.946.0", "@aws-sdk/middleware-host-header": "3.936.0", "@aws-sdk/middleware-logger": "3.936.0", "@aws-sdk/middleware-recursion-detection": "3.936.0", "@aws-sdk/middleware-sdk-ec2": "3.946.0", "@aws-sdk/middleware-user-agent": "3.946.0", "@aws-sdk/region-config-resolver": "3.936.0", "@aws-sdk/types": "3.936.0", "@aws-sdk/util-endpoints": "3.936.0", "@aws-sdk/util-user-agent-browser": "3.936.0", "@aws-sdk/util-user-agent-node": "3.946.0", "@smithy/config-resolver": "^4.4.3", "@smithy/core": "^3.18.7", "@smithy/fetch-http-handler": "^5.3.6", "@smithy/hash-node": "^4.2.5", "@smithy/invalid-dependency": "^4.2.5", "@smithy/middleware-content-length": "^4.2.5", "@smithy/middleware-endpoint": "^4.3.14", "@smithy/middleware-retry": "^4.4.14", "@smithy/middleware-serde": "^4.2.6", "@smithy/middleware-stack": "^4.2.5", "@smithy/node-config-provider": "^4.3.5", "@smithy/node-http-handler": "^4.4.5", "@smithy/protocol-http": "^5.3.5", "@smithy/smithy-client": "^4.9.10", "@smithy/types": "^4.9.0", "@smithy/url-parser": "^4.2.5", "@smithy/util-base64": "^4.3.0", "@smithy/util-body-length-browser": "^4.2.0", "@smithy/util-body-length-node": "^4.2.1", "@smithy/util-defaults-mode-browser": "^4.3.13", "@smithy/util-defaults-mode-node": "^4.2.16", "@smithy/util-endpoints": "^3.2.5", "@smithy/util-middleware": "^4.2.5", "@smithy/util-retry": "^4.2.5", "@smithy/util-utf8": "^4.2.0", "@smithy/util-waiter": "^4.2.5", "tslib": "^2.6.2" } }, "sha512-kHkryE5G72AtkRyGRBh06Dl4eYXQhdTOqTb9umxfe7dCFCYDAPwXGMKPowXHOfXScvLe3Bahs8cYI1cpobGHZA=="], - - "@aws-sdk/client-iam": ["@aws-sdk/[email protected]", "", { "dependencies": { "@aws-crypto/sha256-browser": "5.2.0", "@aws-crypto/sha256-js": "5.2.0", "@aws-sdk/core": "3.946.0", "@aws-sdk/credential-provider-node": "3.946.0", "@aws-sdk/middleware-host-header": "3.936.0", "@aws-sdk/middleware-logger": "3.936.0", "@aws-sdk/middleware-recursion-detection": "3.936.0", "@aws-sdk/middleware-user-agent": "3.946.0", "@aws-sdk/region-config-resolver": "3.936.0", "@aws-sdk/types": "3.936.0", "@aws-sdk/util-endpoints": "3.936.0", "@aws-sdk/util-user-agent-browser": "3.936.0", "@aws-sdk/util-user-agent-node": "3.946.0", "@smithy/config-resolver": "^4.4.3", "@smithy/core": "^3.18.7", "@smithy/fetch-http-handler": "^5.3.6", "@smithy/hash-node": "^4.2.5", "@smithy/invalid-dependency": "^4.2.5", "@smithy/middleware-content-length": "^4.2.5", "@smithy/middleware-endpoint": "^4.3.14", "@smithy/middleware-retry": "^4.4.14", "@smithy/middleware-serde": "^4.2.6", "@smithy/middleware-stack": "^4.2.5", "@smithy/node-config-provider": "^4.3.5", "@smithy/node-http-handler": "^4.4.5", "@smithy/protocol-http": "^5.3.5", "@smithy/smithy-client": "^4.9.10", "@smithy/types": "^4.9.0", "@smithy/url-parser": "^4.2.5", "@smithy/util-base64": "^4.3.0", "@smithy/util-body-length-browser": "^4.2.0", "@smithy/util-body-length-node": "^4.2.1", "@smithy/util-defaults-mode-browser": "^4.3.13", "@smithy/util-defaults-mode-node": "^4.2.16", "@smithy/util-endpoints": "^3.2.5", "@smithy/util-middleware": "^4.2.5", "@smithy/util-retry": "^4.2.5", "@smithy/util-utf8": "^4.2.0", "@smithy/util-waiter": "^4.2.5", "tslib": "^2.6.2" } }, "sha512-Sh/fPctfs+daLvFbYnw2+Hd5ANetCi2dWIl6XoLHhTc4C2SZfnZswEoY0GF4CufCMchfvT+Y4GFOSy/YXpgn7A=="], - "@aws-sdk/client-lambda": ["@aws-sdk/[email protected]", "", { "dependencies": { "@aws-crypto/sha256-browser": "5.2.0", "@aws-crypto/sha256-js": "5.2.0", "@aws-sdk/core": "3.946.0", "@aws-sdk/credential-provider-node": "3.946.0", "@aws-sdk/middleware-host-header": "3.936.0", "@aws-sdk/middleware-logger": "3.936.0", "@aws-sdk/middleware-recursion-detection": "3.936.0", "@aws-sdk/middleware-user-agent": "3.946.0", "@aws-sdk/region-config-resolver": "3.936.0", "@aws-sdk/types": "3.936.0", "@aws-sdk/util-endpoints": "3.936.0", "@aws-sdk/util-user-agent-browser": "3.936.0", "@aws-sdk/util-user-agent-node": "3.946.0", "@smithy/config-resolver": "^4.4.3", "@smithy/core": "^3.18.7", "@smithy/eventstream-serde-browser": "^4.2.5", "@smithy/eventstream-serde-config-resolver": "^4.3.5", "@smithy/eventstream-serde-node": "^4.2.5", "@smithy/fetch-http-handler": "^5.3.6", "@smithy/hash-node": "^4.2.5", "@smithy/invalid-dependency": "^4.2.5", "@smithy/middleware-content-length": "^4.2.5", "@smithy/middleware-endpoint": "^4.3.14", "@smithy/middleware-retry": "^4.4.14", "@smithy/middleware-serde": "^4.2.6", "@smithy/middleware-stack": "^4.2.5", "@smithy/node-config-provider": "^4.3.5", "@smithy/node-http-handler": "^4.4.5", "@smithy/protocol-http": "^5.3.5", "@smithy/smithy-client": "^4.9.10", "@smithy/types": "^4.9.0", "@smithy/url-parser": "^4.2.5", "@smithy/util-base64": "^4.3.0", "@smithy/util-body-length-browser": "^4.2.0", "@smithy/util-body-length-node": "^4.2.1", "@smithy/util-defaults-mode-browser": "^4.3.13", "@smithy/util-defaults-mode-node": "^4.2.16", "@smithy/util-endpoints": "^3.2.5", "@smithy/util-middleware": "^4.2.5", "@smithy/util-retry": "^4.2.5", "@smithy/util-stream": "^4.5.6", "@smithy/util-utf8": "^4.2.0", "@smithy/util-waiter": "^4.2.5", "tslib": "^2.6.2" } }, "sha512-+nGzto4JBhHuElKFe9y5phKKwsSMWHDld3RyoQwryQvPvtNyCz1xPQsTd1gdUTekmvwGMl5EmcHwNdvKkHZ3mg=="], "@aws-sdk/client-s3": ["@aws-sdk/[email protected]", "", { "dependencies": { "@aws-crypto/sha1-browser": "5.2.0", "@aws-crypto/sha256-browser": "5.2.0", "@aws-crypto/sha256-js": "5.2.0", "@aws-sdk/core": "3.946.0", "@aws-sdk/credential-provider-node": "3.946.0", "@aws-sdk/middleware-bucket-endpoint": "3.936.0", "@aws-sdk/middleware-expect-continue": "3.936.0", "@aws-sdk/middleware-flexible-checksums": "3.946.0", "@aws-sdk/middleware-host-header": "3.936.0", "@aws-sdk/middleware-location-constraint": "3.936.0", "@aws-sdk/middleware-logger": "3.936.0", "@aws-sdk/middleware-recursion-detection": "3.936.0", "@aws-sdk/middleware-sdk-s3": "3.946.0", "@aws-sdk/middleware-ssec": "3.936.0", "@aws-sdk/middleware-user-agent": "3.946.0", "@aws-sdk/region-config-resolver": "3.936.0", "@aws-sdk/signature-v4-multi-region": "3.946.0", "@aws-sdk/types": "3.936.0", "@aws-sdk/util-endpoints": "3.936.0", "@aws-sdk/util-user-agent-browser": "3.936.0", "@aws-sdk/util-user-agent-node": "3.946.0", "@smithy/config-resolver": "^4.4.3", "@smithy/core": "^3.18.7", "@smithy/eventstream-serde-browser": "^4.2.5", "@smithy/eventstream-serde-config-resolver": "^4.3.5", "@smithy/eventstream-serde-node": "^4.2.5", "@smithy/fetch-http-handler": "^5.3.6", "@smithy/hash-blob-browser": "^4.2.6", "@smithy/hash-node": "^4.2.5", "@smithy/hash-stream-node": "^4.2.5", "@smithy/invalid-dependency": "^4.2.5", "@smithy/md5-js": "^4.2.5", "@smithy/middleware-content-length": "^4.2.5", "@smithy/middleware-endpoint": "^4.3.14", "@smithy/middleware-retry": "^4.4.14", "@smithy/middleware-serde": "^4.2.6", "@smithy/middleware-stack": "^4.2.5", "@smithy/node-config-provider": "^4.3.5", "@smithy/node-http-handler": "^4.4.5", "@smithy/protocol-http": "^5.3.5", "@smithy/smithy-client": "^4.9.10", "@smithy/types": "^4.9.0", "@smithy/url-parser": "^4.2.5", "@smithy/util-base64": "^4.3.0", "@smithy/util-body-length-browser": "^4.2.0", "@smithy/util-body-length-node": "^4.2.1", "@smithy/util-defaults-mode-browser": "^4.3.13", "@smithy/util-defaults-mode-node": "^4.2.16", "@smithy/util-endpoints": "^3.2.5", "@smithy/util-middleware": "^4.2.5", "@smithy/util-retry": "^4.2.5", "@smithy/util-stream": "^4.5.6", "@smithy/util-utf8": "^4.2.0", "@smithy/util-waiter": "^4.2.5", "tslib": "^2.6.2" } }, "sha512-Y3ww3yd1wzmS2r3qgH3jg4MxCTdeNrae2J1BmdV+IW/2R2gFWJva5U5GbS6KUSUxanJBRG7gd8uOIi1b0EMOng=="], - "@aws-sdk/client-sagemaker": ["@aws-sdk/[email protected]", "", { "dependencies": { "@aws-crypto/sha256-browser": "5.2.0", "@aws-crypto/sha256-js": "5.2.0", "@aws-sdk/core": "3.946.0", "@aws-sdk/credential-provider-node": "3.946.0", "@aws-sdk/middleware-host-header": "3.936.0", "@aws-sdk/middleware-logger": "3.936.0", "@aws-sdk/middleware-recursion-detection": "3.936.0", "@aws-sdk/middleware-user-agent": "3.946.0", "@aws-sdk/region-config-resolver": "3.936.0", "@aws-sdk/types": "3.936.0", "@aws-sdk/util-endpoints": "3.936.0", "@aws-sdk/util-user-agent-browser": "3.936.0", "@aws-sdk/util-user-agent-node": "3.946.0", "@smithy/config-resolver": "^4.4.3", "@smithy/core": "^3.18.7", "@smithy/fetch-http-handler": "^5.3.6", "@smithy/hash-node": "^4.2.5", "@smithy/invalid-dependency": "^4.2.5", "@smithy/middleware-content-length": "^4.2.5", "@smithy/middleware-endpoint": "^4.3.14", "@smithy/middleware-retry": "^4.4.14", "@smithy/middleware-serde": "^4.2.6", "@smithy/middleware-stack": "^4.2.5", "@smithy/node-config-provider": "^4.3.5", "@smithy/node-http-handler": "^4.4.5", "@smithy/protocol-http": "^5.3.5", "@smithy/smithy-client": "^4.9.10", "@smithy/types": "^4.9.0", "@smithy/url-parser": "^4.2.5", "@smithy/util-base64": "^4.3.0", "@smithy/util-body-length-browser": "^4.2.0", "@smithy/util-body-length-node": "^4.2.1", "@smithy/util-defaults-mode-browser": "^4.3.13", "@smithy/util-defaults-mode-node": "^4.2.16", "@smithy/util-endpoints": "^3.2.5", "@smithy/util-middleware": "^4.2.5", "@smithy/util-retry": "^4.2.5", "@smithy/util-utf8": "^4.2.0", "@smithy/util-waiter": "^4.2.5", "tslib": "^2.6.2" } }, "sha512-Cjo0AgJgFqtuutveiGyBArExQ9XHlVEbi1uZNOfYw6t4rFBRXhI5Bnz7pZvjtx+ywHxUcwVqJXDH66XDElcMDQ=="], - - "@aws-sdk/client-ses": ["@aws-sdk/[email protected]", "", { "dependencies": { "@aws-crypto/sha256-browser": "5.2.0", "@aws-crypto/sha256-js": "5.2.0", "@aws-sdk/core": "3.946.0", "@aws-sdk/credential-provider-node": "3.946.0", "@aws-sdk/middleware-host-header": "3.936.0", "@aws-sdk/middleware-logger": "3.936.0", "@aws-sdk/middleware-recursion-detection": "3.936.0", "@aws-sdk/middleware-user-agent": "3.946.0", "@aws-sdk/region-config-resolver": "3.936.0", "@aws-sdk/types": "3.936.0", "@aws-sdk/util-endpoints": "3.936.0", "@aws-sdk/util-user-agent-browser": "3.936.0", "@aws-sdk/util-user-agent-node": "3.946.0", "@smithy/config-resolver": "^4.4.3", "@smithy/core": "^3.18.7", "@smithy/fetch-http-handler": "^5.3.6", "@smithy/hash-node": "^4.2.5", "@smithy/invalid-dependency": "^4.2.5", "@smithy/middleware-content-length": "^4.2.5", "@smithy/middleware-endpoint": "^4.3.14", "@smithy/middleware-retry": "^4.4.14", "@smithy/middleware-serde": "^4.2.6", "@smithy/middleware-stack": "^4.2.5", "@smithy/node-config-provider": "^4.3.5", "@smithy/node-http-handler": "^4.4.5", "@smithy/protocol-http": "^5.3.5", "@smithy/smithy-client": "^4.9.10", "@smithy/types": "^4.9.0", "@smithy/url-parser": "^4.2.5", "@smithy/util-base64": "^4.3.0", "@smithy/util-body-length-browser": "^4.2.0", "@smithy/util-body-length-node": "^4.2.1", "@smithy/util-defaults-mode-browser": "^4.3.13", "@smithy/util-defaults-mode-node": "^4.2.16", "@smithy/util-endpoints": "^3.2.5", "@smithy/util-middleware": "^4.2.5", "@smithy/util-retry": "^4.2.5", "@smithy/util-utf8": "^4.2.0", "@smithy/util-waiter": "^4.2.5", "tslib": "^2.6.2" } }, "sha512-8haC9kzCVjrsgYFLHbvZw0+GF3f9ezkgkUCsGQEGqerBjHSHkm4YB0+Nje1RGrM8PcPVFMnvCXxc+98eGPcvQw=="], - - "@aws-sdk/client-sesv2": ["@aws-sdk/[email protected]", "", { "dependencies": { "@aws-crypto/sha256-browser": "5.2.0", "@aws-crypto/sha256-js": "5.2.0", "@aws-sdk/core": "3.946.0", "@aws-sdk/credential-provider-node": "3.946.0", "@aws-sdk/middleware-host-header": "3.936.0", "@aws-sdk/middleware-logger": "3.936.0", "@aws-sdk/middleware-recursion-detection": "3.936.0", "@aws-sdk/middleware-user-agent": "3.946.0", "@aws-sdk/region-config-resolver": "3.936.0", "@aws-sdk/signature-v4-multi-region": "3.946.0", "@aws-sdk/types": "3.936.0", "@aws-sdk/util-endpoints": "3.936.0", "@aws-sdk/util-user-agent-browser": "3.936.0", "@aws-sdk/util-user-agent-node": "3.946.0", "@smithy/config-resolver": "^4.4.3", "@smithy/core": "^3.18.7", "@smithy/fetch-http-handler": "^5.3.6", "@smithy/hash-node": "^4.2.5", "@smithy/invalid-dependency": "^4.2.5", "@smithy/middleware-content-length": "^4.2.5", "@smithy/middleware-endpoint": "^4.3.14", "@smithy/middleware-retry": "^4.4.14", "@smithy/middleware-serde": "^4.2.6", "@smithy/middleware-stack": "^4.2.5", "@smithy/node-config-provider": "^4.3.5", "@smithy/node-http-handler": "^4.4.5", "@smithy/protocol-http": "^5.3.5", "@smithy/smithy-client": "^4.9.10", "@smithy/types": "^4.9.0", "@smithy/url-parser": "^4.2.5", "@smithy/util-base64": "^4.3.0", "@smithy/util-body-length-browser": "^4.2.0", "@smithy/util-body-length-node": "^4.2.1", "@smithy/util-defaults-mode-browser": "^4.3.13", "@smithy/util-defaults-mode-node": "^4.2.16", "@smithy/util-endpoints": "^3.2.5", "@smithy/util-middleware": "^4.2.5", "@smithy/util-retry": "^4.2.5", "@smithy/util-utf8": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-JYj3BPqgyRXgBjZ3Xvo4Abd+vLxcsHe4gb0TvwiSM/k7e6MRgBZoYwDOnwbNDs/62X1sn7MPHqqB3miuO4nR5g=="], - "@aws-sdk/client-sqs": ["@aws-sdk/[email protected]", "", { "dependencies": { "@aws-crypto/sha256-browser": "5.2.0", "@aws-crypto/sha256-js": "5.2.0", "@aws-sdk/core": "3.946.0", "@aws-sdk/credential-provider-node": "3.946.0", "@aws-sdk/middleware-host-header": "3.936.0", "@aws-sdk/middleware-logger": "3.936.0", "@aws-sdk/middleware-recursion-detection": "3.936.0", "@aws-sdk/middleware-sdk-sqs": "3.946.0", "@aws-sdk/middleware-user-agent": "3.946.0", "@aws-sdk/region-config-resolver": "3.936.0", "@aws-sdk/types": "3.936.0", "@aws-sdk/util-endpoints": "3.936.0", "@aws-sdk/util-user-agent-browser": "3.936.0", "@aws-sdk/util-user-agent-node": "3.946.0", "@smithy/config-resolver": "^4.4.3", "@smithy/core": "^3.18.7", "@smithy/fetch-http-handler": "^5.3.6", "@smithy/hash-node": "^4.2.5", "@smithy/invalid-dependency": "^4.2.5", "@smithy/md5-js": "^4.2.5", "@smithy/middleware-content-length": "^4.2.5", "@smithy/middleware-endpoint": "^4.3.14", "@smithy/middleware-retry": "^4.4.14", "@smithy/middleware-serde": "^4.2.6", "@smithy/middleware-stack": "^4.2.5", "@smithy/node-config-provider": "^4.3.5", "@smithy/node-http-handler": "^4.4.5", "@smithy/protocol-http": "^5.3.5", "@smithy/smithy-client": "^4.9.10", "@smithy/types": "^4.9.0", "@smithy/url-parser": "^4.2.5", "@smithy/util-base64": "^4.3.0", "@smithy/util-body-length-browser": "^4.2.0", "@smithy/util-body-length-node": "^4.2.1", "@smithy/util-defaults-mode-browser": "^4.3.13", "@smithy/util-defaults-mode-node": "^4.2.16", "@smithy/util-endpoints": "^3.2.5", "@smithy/util-middleware": "^4.2.5", "@smithy/util-retry": "^4.2.5", "@smithy/util-utf8": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-Ou9F7iERMw2+1xehtXcwcOPhbd5XIBXWg7c/VyZYeE9+H81FxOc8g0hum98iiAUQ0GALce38T+R1FpP0LBbTSA=="], - "@aws-sdk/client-ssm": ["@aws-sdk/[email protected]", "", { "dependencies": { "@aws-crypto/sha256-browser": "5.2.0", "@aws-crypto/sha256-js": "5.2.0", "@aws-sdk/core": "3.946.0", "@aws-sdk/credential-provider-node": "3.946.0", "@aws-sdk/middleware-host-header": "3.936.0", "@aws-sdk/middleware-logger": "3.936.0", "@aws-sdk/middleware-recursion-detection": "3.936.0", "@aws-sdk/middleware-user-agent": "3.946.0", "@aws-sdk/region-config-resolver": "3.936.0", "@aws-sdk/types": "3.936.0", "@aws-sdk/util-endpoints": "3.936.0", "@aws-sdk/util-user-agent-browser": "3.936.0", "@aws-sdk/util-user-agent-node": "3.946.0", "@smithy/config-resolver": "^4.4.3", "@smithy/core": "^3.18.7", "@smithy/fetch-http-handler": "^5.3.6", "@smithy/hash-node": "^4.2.5", "@smithy/invalid-dependency": "^4.2.5", "@smithy/middleware-content-length": "^4.2.5", "@smithy/middleware-endpoint": "^4.3.14", "@smithy/middleware-retry": "^4.4.14", "@smithy/middleware-serde": "^4.2.6", "@smithy/middleware-stack": "^4.2.5", "@smithy/node-config-provider": "^4.3.5", "@smithy/node-http-handler": "^4.4.5", "@smithy/protocol-http": "^5.3.5", "@smithy/smithy-client": "^4.9.10", "@smithy/types": "^4.9.0", "@smithy/url-parser": "^4.2.5", "@smithy/util-base64": "^4.3.0", "@smithy/util-body-length-browser": "^4.2.0", "@smithy/util-body-length-node": "^4.2.1", "@smithy/util-defaults-mode-browser": "^4.3.13", "@smithy/util-defaults-mode-node": "^4.2.16", "@smithy/util-endpoints": "^3.2.5", "@smithy/util-middleware": "^4.2.5", "@smithy/util-retry": "^4.2.5", "@smithy/util-utf8": "^4.2.0", "@smithy/util-waiter": "^4.2.5", "tslib": "^2.6.2" } }, "sha512-pXBHu9mq8WJzny3vgtjKUmo2OXsQLlaDjFuBQCapijZrtOq5Bu2fx2EEtTMAR3/TMBCIeqNAPEr5udlOiTdoRw=="], - "@aws-sdk/client-sso": ["@aws-sdk/[email protected]", "", { "dependencies": { "@aws-crypto/sha256-browser": "5.2.0", "@aws-crypto/sha256-js": "5.2.0", "@aws-sdk/core": "3.946.0", "@aws-sdk/middleware-host-header": "3.936.0", "@aws-sdk/middleware-logger": "3.936.0", "@aws-sdk/middleware-recursion-detection": "3.936.0", "@aws-sdk/middleware-user-agent": "3.946.0", "@aws-sdk/region-config-resolver": "3.936.0", "@aws-sdk/types": "3.936.0", "@aws-sdk/util-endpoints": "3.936.0", "@aws-sdk/util-user-agent-browser": "3.936.0", "@aws-sdk/util-user-agent-node": "3.946.0", "@smithy/config-resolver": "^4.4.3", "@smithy/core": "^3.18.7", "@smithy/fetch-http-handler": "^5.3.6", "@smithy/hash-node": "^4.2.5", "@smithy/invalid-dependency": "^4.2.5", "@smithy/middleware-content-length": "^4.2.5", "@smithy/middleware-endpoint": "^4.3.14", "@smithy/middleware-retry": "^4.4.14", "@smithy/middleware-serde": "^4.2.6", "@smithy/middleware-stack": "^4.2.5", "@smithy/node-config-provider": "^4.3.5", "@smithy/node-http-handler": "^4.4.5", "@smithy/protocol-http": "^5.3.5", "@smithy/smithy-client": "^4.9.10", "@smithy/types": "^4.9.0", "@smithy/url-parser": "^4.2.5", "@smithy/util-base64": "^4.3.0", "@smithy/util-body-length-browser": "^4.2.0", "@smithy/util-body-length-node": "^4.2.1", "@smithy/util-defaults-mode-browser": "^4.3.13", "@smithy/util-defaults-mode-node": "^4.2.16", "@smithy/util-endpoints": "^3.2.5", "@smithy/util-middleware": "^4.2.5", "@smithy/util-retry": "^4.2.5", "@smithy/util-utf8": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-kGAs5iIVyUz4p6TX3pzG5q3cNxXnVpC4pwRC6DCSaSv9ozyPjc2d74FsK4fZ+J+ejtvCdJk72uiuQtWJc86Wuw=="], "@aws-sdk/client-sts": ["@aws-sdk/[email protected]", "", { "dependencies": { "@aws-crypto/sha256-browser": "3.0.0", "@aws-crypto/sha256-js": "3.0.0", "@aws-sdk/credential-provider-node": "3.398.0", "@aws-sdk/middleware-host-header": "3.398.0", "@aws-sdk/middleware-logger": "3.398.0", "@aws-sdk/middleware-recursion-detection": "3.398.0", "@aws-sdk/middleware-sdk-sts": "3.398.0", "@aws-sdk/middleware-signing": "3.398.0", "@aws-sdk/middleware-user-agent": "3.398.0", "@aws-sdk/types": "3.398.0", "@aws-sdk/util-endpoints": "3.398.0", "@aws-sdk/util-user-agent-browser": "3.398.0", "@aws-sdk/util-user-agent-node": "3.398.0", "@smithy/config-resolver": "^2.0.5", "@smithy/fetch-http-handler": "^2.0.5", "@smithy/hash-node": "^2.0.5", "@smithy/invalid-dependency": "^2.0.5", "@smithy/middleware-content-length": "^2.0.5", "@smithy/middleware-endpoint": "^2.0.5", "@smithy/middleware-retry": "^2.0.5", "@smithy/middleware-serde": "^2.0.5", "@smithy/middleware-stack": "^2.0.0", "@smithy/node-config-provider": "^2.0.5", "@smithy/node-http-handler": "^2.0.5", "@smithy/protocol-http": "^2.0.5", "@smithy/smithy-client": "^2.0.5", "@smithy/types": "^2.2.2", "@smithy/url-parser": "^2.0.5", "@smithy/util-base64": "^2.0.0", "@smithy/util-body-length-browser": "^2.0.0", "@smithy/util-body-length-node": "^2.1.0", "@smithy/util-defaults-mode-browser": "^2.0.5", "@smithy/util-defaults-mode-node": "^2.0.5", "@smithy/util-retry": "^2.0.0", "@smithy/util-utf8": "^2.0.0", "fast-xml-parser": "4.2.5", "tslib": "^2.5.0" } }, "sha512-/3Pa9wLMvBZipKraq3AtbmTfXW6q9kyvhwOno64f1Fz7kFb8ijQFMGoATS70B2pGEZTlxkUqJFWDiisT6Q6dFg=="], @@ -466,8 +456,6 @@ "@aws-sdk/middleware-recursion-detection": ["@aws-sdk/[email protected]", "", { "dependencies": { "@aws-sdk/types": "3.936.0", "@aws/lambda-invoke-store": "^0.2.0", "@smithy/protocol-http": "^5.3.5", "@smithy/types": "^4.9.0", "tslib": "^2.6.2" } }, "sha512-l4aGbHpXM45YNgXggIux1HgsCVAvvBoqHPkqLnqMl9QVapfuSTjJHfDYDsx1Xxct6/m7qSMUzanBALhiaGO2fA=="], - "@aws-sdk/middleware-sdk-ec2": ["@aws-sdk/[email protected]", "", { "dependencies": { "@aws-sdk/types": "3.936.0", "@aws-sdk/util-format-url": "3.936.0", "@smithy/middleware-endpoint": "^4.3.14", "@smithy/protocol-http": "^5.3.5", "@smithy/signature-v4": "^5.3.5", "@smithy/smithy-client": "^4.9.10", "@smithy/types": "^4.9.0", "tslib": "^2.6.2" } }, "sha512-dFJMEnXcb0amuSK6YsTR3Vx6YUkwOOdzSYH12OARwvpPjlovJC+s0eB5TRgwP/easWE+ceAoR2BvbH/aedWMVw=="], - "@aws-sdk/middleware-sdk-s3": ["@aws-sdk/[email protected]", "", { "dependencies": { "@aws-sdk/core": "3.946.0", "@aws-sdk/types": "3.936.0", "@aws-sdk/util-arn-parser": "3.893.0", "@smithy/core": "^3.18.7", "@smithy/node-config-provider": "^4.3.5", "@smithy/protocol-http": "^5.3.5", "@smithy/signature-v4": "^5.3.5", "@smithy/smithy-client": "^4.9.10", "@smithy/types": "^4.9.0", "@smithy/util-config-provider": "^4.2.0", "@smithy/util-middleware": "^4.2.5", "@smithy/util-stream": "^4.5.6", "@smithy/util-utf8": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-0UTFmFd8PX2k/jLu/DBmR+mmLQWAtUGHYps9Rjx3dcXNwaMLaa/39NoV3qn7Dwzfpqc6JZlZzBk+NDOCJIHW9g=="], "@aws-sdk/middleware-sdk-sqs": ["@aws-sdk/[email protected]", "", { "dependencies": { "@aws-sdk/types": "3.936.0", "@smithy/smithy-client": "^4.9.10", "@smithy/types": "^4.9.0", "@smithy/util-hex-encoding": "^4.2.0", "@smithy/util-utf8": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-+KedlcXUqA1Bdafvw264SWvwyHYvFxn47y831tEKc85fp5VF5LGE9uMlU13hsWySftLmDd/ZFwSQI6RN2zSpAg=="], @@ -494,8 +482,6 @@ "@aws-sdk/util-endpoints": ["@aws-sdk/[email protected]", "", { "dependencies": { "@aws-sdk/types": "3.936.0", "@smithy/types": "^4.9.0", "@smithy/url-parser": "^4.2.5", "@smithy/util-endpoints": "^3.2.5", "tslib": "^2.6.2" } }, "sha512-0Zx3Ntdpu+z9Wlm7JKUBOzS9EunwKAb4KdGUQQxDqh5Lc3ta5uBoub+FgmVuzwnmBu9U1Os8UuwVTH0Lgu+P5w=="], - "@aws-sdk/util-format-url": ["@aws-sdk/[email protected]", "", { "dependencies": { "@aws-sdk/types": "3.936.0", "@smithy/querystring-builder": "^4.2.5", "@smithy/types": "^4.9.0", "tslib": "^2.6.2" } }, "sha512-MS5eSEtDUFIAMHrJaMERiHAvDPdfxc/T869ZjDNFAIiZhyc037REw0aoTNeimNXDNy2txRNZJaAUn/kE4RwN+g=="], - "@aws-sdk/util-locate-window": ["@aws-sdk/[email protected]", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-T89pFfgat6c8nMmpI8eKjBcDcgJq36+m9oiXbcUzeU55MP9ZuGgBomGjGnHaEyF36jenW9gmg3NfZDm0AO2XPg=="], "@aws-sdk/util-user-agent-browser": ["@aws-sdk/[email protected]", "", { "dependencies": { "@aws-sdk/types": "3.936.0", "@smithy/types": "^4.9.0", "bowser": "^2.11.0", "tslib": "^2.6.2" } }, "sha512-eZ/XF6NxMtu+iCma58GRNRxSq4lHo6zHQLOZRIeL/ghqYJirqHdenMOwrzPettj60KWlv827RVebP9oNVrwZbw=="], @@ -612,21 +598,21 @@ "@chevrotain/utils": ["@chevrotain/[email protected]", "", {}, "sha512-YslZMgtJUyuMbZ+aKvfF3x1f5liK4mWNxghFRv7jqRR9C3R3fAOGTTKvxXDa2Y1s9zSbcpuO0cAxDYsc9SrXoQ=="], - "@cloudflare/kv-asset-handler": ["@cloudflare/[email protected]", "", { "dependencies": { "mime": "^3.0.0" } }, "sha512-+tv3z+SPp+gqTIcImN9o0hqE9xyfQjI1XD9pL6NuKjua9B1y7mNYv0S9cP+QEbA4ppVgGZEmKOvHX5G5Ei1CVA=="], + "@cloudflare/kv-asset-handler": ["@cloudflare/[email protected]", "", { "dependencies": { "mime": "^3.0.0" } }, "sha512-Nu8ahitGFFJztxUml9oD/DLb7Z28C8cd8F46IVQ7y5Btz575pvMY8AqZsXkX7Gds29eCKdMgIHjIvzskHgPSFg=="], - "@cloudflare/unenv-preset": ["@cloudflare/[email protected]", "", { "peerDependencies": { "unenv": "2.0.0-rc.17", "workerd": "^1.20250508.0" }, "optionalPeers": ["workerd"] }, "sha512-/M3MEcj3V2WHIRSW1eAQBPRJ6JnGQHc6JKMAPLkDb7pLs3m6X9ES/+K3ceGqxI6TKeF32AWAi7ls0AYzVxCP0A=="], + "@cloudflare/unenv-preset": ["@cloudflare/[email protected]", "", { "peerDependencies": { "unenv": "2.0.0-rc.24", "workerd": "^1.20251202.0" }, "optionalPeers": ["workerd"] }, "sha512-NulO1H8R/DzsJguLC0ndMuk4Ufv0KSlN+E54ay9rn9ZCQo0kpAPwwh3LhgpZ96a3Dr6L9LqW57M4CqC34iLOvw=="], - "@cloudflare/workerd-darwin-64": ["@cloudflare/[email protected]", "", { "os": "darwin", "cpu": "x64" }, "sha512-toG8JUKVLIks4oOJLe9FeuixE84pDpMZ32ip7mCpE7JaFc5BqGFvevk0YC/db3T71AQlialjRwioH3jS/dzItA=="], + "@cloudflare/workerd-darwin-64": ["@cloudflare/[email protected]", "", { "os": "darwin", "cpu": "x64" }, "sha512-/uvEAWEukTWb1geHhbjGUeZqcSSSyYzp0mvoPUBl+l0ont4NVGao3fgwM0q8wtKvgoKCHSG6zcG23wj9Opj3Nw=="], - "@cloudflare/workerd-darwin-arm64": ["@cloudflare/[email protected]", "", { "os": "darwin", "cpu": "arm64" }, "sha512-JTX0exbC9/ZtMmQQA8tDZEZFMXZrxOpTUj2hHnsUkErWYkr5SSZH04RBhPg6dU4VL8bXuB5/eJAh7+P9cZAp7g=="], + "@cloudflare/workerd-darwin-arm64": ["@cloudflare/[email protected]", "", { "os": "darwin", "cpu": "arm64" }, "sha512-f52xRvcI9cWRd6400EZStRtXiRC5XKEud7K5aFIbbUv0VeINltujFQQ9nHWtsF6g1quIXWkjhh5u01gPAYNNXA=="], - "@cloudflare/workerd-linux-64": ["@cloudflare/[email protected]", "", { "os": "linux", "cpu": "x64" }, "sha512-8jkSoVRJ+1bOx3tuWlZCGaGCV2ew7/jFMl6V3CPXOoEtERUHsZBQLVkQIGKcmC/LKSj7f/mpyBUeu2EPTo2HEg=="], + "@cloudflare/workerd-linux-64": ["@cloudflare/[email protected]", "", { "os": "linux", "cpu": "x64" }, "sha512-HYXinF5RBH7oXbsFUMmwKCj+WltpYbf5mRKUBG5v3EuPhUjSIFB84U+58pDyfBJjcynHdy3EtvTWcvh/+lcgow=="], - "@cloudflare/workerd-linux-arm64": ["@cloudflare/[email protected]", "", { "os": "linux", "cpu": "arm64" }, "sha512-YAzcOyu897z5dQKFzme1oujGWMGEJCR7/Wrrm1nSP6dqutxFPTubRADM8BHn2CV3ij//vaPnAeLmZE3jVwOwig=="], + "@cloudflare/workerd-linux-arm64": ["@cloudflare/[email protected]", "", { "os": "linux", "cpu": "arm64" }, "sha512-++L02Jdoxz7hEA9qDaQjbVU1RzQS+S+eqIi22DkPe2Tgiq2M3UfNpeu+75k5L9DGRIkZPYvwMBMbcmKvQqdIIg=="], - "@cloudflare/workerd-windows-64": ["@cloudflare/[email protected]", "", { "os": "win32", "cpu": "x64" }, "sha512-XWM/6sagDrO0CYDKhXhPjM23qusvIN1ju9ZEml6gOQs8tNOFnq6Cn6X9FAmnyapRFCGUSEC3HZYJAm7zwVKaMA=="], + "@cloudflare/workerd-windows-64": ["@cloudflare/[email protected]", "", { "os": "win32", "cpu": "x64" }, "sha512-gzeU6eDydTi7ib+Q9DD/c0hpXtqPucnHk2tfGU03mljPObYxzMkkPGgB5qxpksFvub3y4K0ChjqYxGJB4F+j3g=="], - "@cloudflare/workers-shared": ["@cloudflare/[email protected]", "", { "dependencies": { "mime": "^3.0.0", "zod": "^3.22.3" } }, "sha512-e2tjozEy3/8JnPcddYFuMjW9As+aX0i7egciPE8b+mufS33QCtdFEzZKCK8utFzby0tx9TkxGFLJ+cmSrJ+tLw=="], + "@cloudflare/workers-types": ["@cloudflare/[email protected]", "", {}, "sha512-r7oxkFjbMcmzhIrzjXaiJlGFDmmeu3+GlwkLlZbUxVWrXHTCkvqu+DrWnNmF6xZEf9j+2/PpuKIS21J522xhJA=="], "@cspotcode/source-map-support": ["@cspotcode/[email protected]", "", { "dependencies": { "@jridgewell/trace-mapping": "0.3.9" } }, "sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw=="], @@ -728,8 +714,6 @@ "@essentials/request-timeout": ["@essentials/[email protected]", "", { "dependencies": { "@essentials/raf": "^1.2.0" } }, "sha512-lKZPhKScNFnR1MBnk4+sxshk46fpvdN+Uh1LlKWFO5g1ocuz4EcknNIL7tm/rsCAs/+xMWiBTwbDUvm+pDNlXw=="], - "@fastify/busboy": ["@fastify/[email protected]", "", {}, "sha512-vBZP4NlzfOlerQTnba4aqZoMhE/a9HY7HRqoOPaETQcSQuWEIyZMHGfVu6w9wGtGK5fED5qRs2DteVCjOH60sA=="], - "@floating-ui/core": ["@floating-ui/[email protected]", "", { "dependencies": { "@floating-ui/utils": "^0.2.10" } }, "sha512-sGnvb5dmrJaKEZ+LDIpguvdX3bDlEllmv4/ClQ9awcmCZrlx5jQyyMWFM5kBI+EyNOCDDiKk8il0zeuX3Zlg/w=="], "@floating-ui/dom": ["@floating-ui/[email protected]", "", { "dependencies": { "@floating-ui/core": "^1.7.3", "@floating-ui/utils": "^0.2.10" } }, "sha512-OOchDgh4F2CchOX94cRVqhvy7b3AFb+/rQXyswmzmGakRfkMgoWVjfnLWkRirfLEfuD4ysVW16eXzwt3jHIzKA=="], @@ -1300,6 +1284,8 @@ "@scalar/types": ["@scalar/[email protected]", "", { "dependencies": { "nanoid": "5.1.5", "type-fest": "5.0.0", "zod": "4.1.11" } }, "sha512-+BSZlfDc5tqFnB+MEJ16o5x86PkKfRK4UYgEv9T5LYmaGmStZF110GoYNbUW6lWRmjFzdPyqS8S7Tijwqd7hXA=="], + "@sec-ant/readable-stream": ["@sec-ant/[email protected]", "", {}, "sha512-831qok9r2t8AlxLko40y2ebgSDhenenCatLVeW/uBtnHPyhHOvG0C7TvfgecV+wHzIm5KUICgzmVpWS+IMEAeg=="], + "@selderee/plugin-htmlparser2": ["@selderee/[email protected]", "", { "dependencies": { "domhandler": "^5.0.3", "selderee": "^0.11.0" } }, "sha512-P33hHGdldxGabLFjPPpaTxVolMrzrcegejx+0GxjrIb9Zv48D8yAIA/QTDR2dFl7Uz7urX8aX6+5bCZslr+gWQ=="], "@sentry-internal/browser-utils": ["@sentry-internal/[email protected]", "", { "dependencies": { "@sentry/core": "10.29.0" } }, "sha512-M3kycMY6f3KY9a8jDYac+yG0E3ZgWVWSxlOEC5MhYyX+g7mqxkwrb3LFQyuxSm/m+CCgMTCaPOOaB2twXP6EQg=="], @@ -1370,6 +1356,8 @@ "@sindresorhus/is": ["@sindresorhus/[email protected]", "", {}, "sha512-rO92VvpgMc3kfiTjGT52LEtJ8Yc5kCWhZjLQ3LwlA4pSgPpQO7bVpYXParOD8Jwf+cVQECJo3yP/4I8aZtUQTQ=="], + "@sindresorhus/merge-streams": ["@sindresorhus/[email protected]", "", {}, "sha512-tlqY9xq5ukxTUZBmoOp+m61cqwQD5pHJtFY3Mn8CA8ps6yghLH/Hw8UPdqg4OLmFW3IFlcXnQNmo/dh8HzXYIQ=="], + "@sindresorhus/slugify": ["@sindresorhus/[email protected]", "", { "dependencies": { "@sindresorhus/transliterate": "^1.0.0", "escape-string-regexp": "^5.0.0" } }, "sha512-9Vybc/qX8Kj6pxJaapjkFbiUJPk7MAkCh/GFCxIBnnsuYCFPIXKvnLidG8xlepht3i24L5XemUmGtrJ3UWrl6w=="], "@sindresorhus/transliterate": ["@sindresorhus/[email protected]", "", { "dependencies": { "escape-string-regexp": "^5.0.0" } }, "sha512-doH1gimEu3A46VX6aVxpHTeHrytJAG6HgdxntYnCFiIFHEM/ZGpG8KiZGBChchjQmG0XFIBL552kBTjVcMZXwQ=="], @@ -1472,7 +1460,7 @@ "@smithy/util-utf8": ["@smithy/[email protected]", "", { "dependencies": { "@smithy/util-buffer-from": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-zBPfuzoI8xyBtR2P6WQj63Rz8i3AmfAaJLuNG8dWsfvPe8lO4aCPYLn879mEgHndZH1zQ2oXmG8O1GGzzaoZiw=="], - "@smithy/util-waiter": ["@smithy/[email protected]", "", { "dependencies": { "@smithy/abort-controller": "^4.2.5", "@smithy/types": "^4.9.0", "tslib": "^2.6.2" } }, "sha512-Dbun99A3InifQdIrsXZ+QLcC0PGBPAdrl4cj1mTgJvyc9N2zf7QSxg8TBkzsCmGJdE3TLbO9ycwpY0EkWahQ/g=="], + "@smithy/util-waiter": ["@smithy/[email protected]", "", { "dependencies": { "@smithy/abort-controller": "^2.2.0", "@smithy/types": "^2.12.0", "tslib": "^2.6.2" } }, "sha512-IHk53BVw6MPMi2Gsn+hCng8rFA3ZmR3Rk7GllxDUW9qFJl/hiSvskn7XldkECapQVkIg/1dHpMAxI9xSTaLLSA=="], "@smithy/uuid": ["@smithy/[email protected]", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-4aUIteuyxtBUhVdiQqcDhKFitwfd9hqoSDYY2KRXiWtgoWJ9Bmise+KfEPDiVHWeJepvF8xJO9/9+WDIciMFFw=="], @@ -1518,34 +1506,8 @@ "@supermemory/tools": ["@supermemory/tools@workspace:packages/tools"], - "@swc/core": ["@swc/[email protected]", "", { "dependencies": { "@swc/counter": "^0.1.3", "@swc/types": "^0.1.25" }, "optionalDependencies": { "@swc/core-darwin-arm64": "1.15.3", "@swc/core-darwin-x64": "1.15.3", "@swc/core-linux-arm-gnueabihf": "1.15.3", "@swc/core-linux-arm64-gnu": "1.15.3", "@swc/core-linux-arm64-musl": "1.15.3", "@swc/core-linux-x64-gnu": "1.15.3", "@swc/core-linux-x64-musl": "1.15.3", "@swc/core-win32-arm64-msvc": "1.15.3", "@swc/core-win32-ia32-msvc": "1.15.3", "@swc/core-win32-x64-msvc": "1.15.3" }, "peerDependencies": { "@swc/helpers": ">=0.5.17" }, "optionalPeers": ["@swc/helpers"] }, "sha512-Qd8eBPkUFL4eAONgGjycZXj1jFCBW8Fd+xF0PzdTlBCWQIV1xnUT7B93wUANtW3KGjl3TRcOyxwSx/u/jyKw/Q=="], - - "@swc/core-darwin-arm64": ["@swc/[email protected]", "", { "os": "darwin", "cpu": "arm64" }, "sha512-AXfeQn0CvcQ4cndlIshETx6jrAM45oeUrK8YeEY6oUZU/qzz0Id0CyvlEywxkWVC81Ajpd8TQQ1fW5yx6zQWkQ=="], - - "@swc/core-darwin-x64": ["@swc/[email protected]", "", { "os": "darwin", "cpu": "x64" }, "sha512-p68OeCz1ui+MZYG4wmfJGvcsAcFYb6Sl25H9TxWl+GkBgmNimIiRdnypK9nBGlqMZAcxngNPtnG3kEMNnvoJ2A=="], - - "@swc/core-linux-arm-gnueabihf": ["@swc/[email protected]", "", { "os": "linux", "cpu": "arm" }, "sha512-Nuj5iF4JteFgwrai97mUX+xUOl+rQRHqTvnvHMATL/l9xE6/TJfPBpd3hk/PVpClMXG3Uvk1MxUFOEzM1JrMYg=="], - - "@swc/core-linux-arm64-gnu": ["@swc/[email protected]", "", { "os": "linux", "cpu": "arm64" }, "sha512-2Nc/s8jE6mW2EjXWxO/lyQuLKShcmTrym2LRf5Ayp3ICEMX6HwFqB1EzDhwoMa2DcUgmnZIalesq2lG3krrUNw=="], - - "@swc/core-linux-arm64-musl": ["@swc/[email protected]", "", { "os": "linux", "cpu": "arm64" }, "sha512-j4SJniZ/qaZ5g8op+p1G9K1z22s/EYGg1UXIb3+Cg4nsxEpF5uSIGEE4mHUfA70L0BR9wKT2QF/zv3vkhfpX4g=="], - - "@swc/core-linux-x64-gnu": ["@swc/[email protected]", "", { "os": "linux", "cpu": "x64" }, "sha512-aKttAZnz8YB1VJwPQZtyU8Uk0BfMP63iDMkvjhJzRZVgySmqt/apWSdnoIcZlUoGheBrcqbMC17GGUmur7OT5A=="], - - "@swc/core-linux-x64-musl": ["@swc/[email protected]", "", { "os": "linux", "cpu": "x64" }, "sha512-oe8FctPu1gnUsdtGJRO2rvOUIkkIIaHqsO9xxN0bTR7dFTlPTGi2Fhk1tnvXeyAvCPxLIcwD8phzKg6wLv9yug=="], - - "@swc/core-win32-arm64-msvc": ["@swc/[email protected]", "", { "os": "win32", "cpu": "arm64" }, "sha512-L9AjzP2ZQ/Xh58e0lTRMLvEDrcJpR7GwZqAtIeNLcTK7JVE+QineSyHp0kLkO1rttCHyCy0U74kDTj0dRz6raA=="], - - "@swc/core-win32-ia32-msvc": ["@swc/[email protected]", "", { "os": "win32", "cpu": "ia32" }, "sha512-B8UtogMzErUPDWUoKONSVBdsgKYd58rRyv2sHJWKOIMCHfZ22FVXICR4O/VwIYtlnZ7ahERcjayBHDlBZpR0aw=="], - - "@swc/core-win32-x64-msvc": ["@swc/[email protected]", "", { "os": "win32", "cpu": "x64" }, "sha512-SpZKMR9QBTecHeqpzJdYEfgw30Oo8b/Xl6rjSzBt1g0ZsXyy60KLXrp6IagQyfTYqNYE/caDvwtF2FPn7pomog=="], - - "@swc/counter": ["@swc/[email protected]", "", {}, "sha512-e2BR4lsJkkRlKZ/qCHPw9ZaSxc0MVUd7gtbtaB7aMvHeJVYe8sOB8DBZkP2DtISHGSku9sCK6T6cnY0CtXrOCQ=="], - "@swc/helpers": ["@swc/[email protected]", "", { "dependencies": { "tslib": "^2.8.0" } }, "sha512-JQ5TuMi45Owi4/BIMAJBoSQoOJu12oOk/gADqlcUL9JEdHB8vyjUSsxqeNXnmXHjYKMi2WcYtezGEEhqUI/E2g=="], - "@swc/types": ["@swc/[email protected]", "", { "dependencies": { "@swc/counter": "^0.1.3" } }, "sha512-iAoY/qRhNH8a/hBvm3zKj9qQ4oc2+3w1unPJa2XvTK3XjeLXtzcCingVPw/9e5mn1+0yPqxcBGp9Jf0pkfMb1g=="], - "@szmarczak/http-timer": ["@szmarczak/[email protected]", "", { "dependencies": { "defer-to-connect": "^2.0.1" } }, "sha512-+PmQX0PiAYPMeVYe237LJAYvOMYW1j2rH5YROyS3b4CTVJum34HfRvKvAzozHAQG0TnHNdUfY9nCeUyRAs//cw=="], "@tailwindcss/node": ["@tailwindcss/[email protected]", "", { "dependencies": { "@jridgewell/remapping": "^2.3.4", "enhanced-resolve": "^5.18.3", "jiti": "^2.6.1", "lightningcss": "1.30.2", "magic-string": "^0.30.21", "source-map-js": "^1.2.1", "tailwindcss": "4.1.17" } }, "sha512-csIkHIgLb3JisEFQ0vxr2Y57GUNYh447C8xzwj89U/8fdW8LhProdxvnVH6U8M2Y73QKiTIH+LWbK3V2BBZsAg=="], @@ -1912,7 +1874,7 @@ "ajv-keywords": ["[email protected]", "", { "dependencies": { "fast-deep-equal": "^3.1.3" }, "peerDependencies": { "ajv": "^8.8.2" } }, "sha512-YCS/JNFAUyr5vAuhk1DWm1CBxRHW9LbJ2ozWeemrIqpbsqKjHVxYPyi5GC0rjZIT5JxJ3virVTS8wk4i/Z+krw=="], - "alchemy": ["[email protected]", "", { "dependencies": { "@aws-sdk/credential-providers": "^3.0.0", "@cloudflare/unenv-preset": "^2.4.0", "@cloudflare/workers-shared": "^0.17.5", "@iarna/toml": "^2.2.5", "@smithy/node-config-provider": "^4.0.0", "@swc/core": "^1.11.24", "aws4fetch": "^1.0.20", "diff": "^8.0.2", "esbuild": "^0.25.1", "fast-json-patch": "^3.1.1", "fast-xml-parser": "^5.2.5", "glob": "^10.0.0", "jszip": "^3.0.0", "kleur": "^4.1.5", "libsodium-wrappers": "^0.7.15", "miniflare": "^4.20250712.0", "neverthrow": "^8.2.0", "open": "^10.1.2", "openapi-types": "^12.1.3", "pathe": "^2.0.3", "turndown": "^7.0.0", "unenv": "2.0.0-rc.15", "ws": "^8.18.3", "xdg-app-paths": "^8.3.0", "yaml": "^2.0.0" }, "peerDependencies": { "@ai-sdk/openai": "^1.1.9", "@ai-sdk/openai-compatible": "^0.2.2", "@aws-sdk/client-dynamodb": "^3.0.0", "@aws-sdk/client-ec2": "^3.0.0", "@aws-sdk/client-iam": "^3.0.0", "@aws-sdk/client-lambda": "^3.0.0", "@aws-sdk/client-s3": "^3.0.0", "@aws-sdk/client-sagemaker": "^3.0.0", "@aws-sdk/client-ses": "^3.0.0", "@aws-sdk/client-sesv2": "^3.0.0", "@aws-sdk/client-sqs": "^3.0.0", "@aws-sdk/client-ssm": "^3.0.0", "@aws-sdk/client-sts": "^3.0.0", "@libsql/client": "^0.15.9", "@octokit/rest": "^21.1.1", "ai": "^4.0.0", "arktype": "^2.0.0", "cloudflare": "^4.0.0", "drizzle-orm": "^0.44.2", "execa": "^9.6.0", "hono": "^4.0.0", "prettier": "^3.0.0", "stripe": "^17.0.0" }, "bin": { "alchemy": "bin/alchemy.js" } }, "sha512-cF/DLJXuvj5hXCUl4AC1NvBVuj/hR1c2LyNUU91NXUMo1zgIvUHmpo/emO7laVXzJUKXB6lRzqj7EwDhVUgQVw=="], + "alchemy": ["[email protected]", "", { "dependencies": { "@aws-sdk/credential-providers": "^3.0.0", "@cloudflare/unenv-preset": "2.7.7", "@cloudflare/workers-types": "^4.20250805.0", "@iarna/toml": "^2.2.5", "@octokit/rest": "^21.1.1", "@smithy/node-config-provider": "^4.0.0", "@smithy/types": "^4.6.0", "aws4fetch": "^1.0.20", "env-paths": "^3.0.0", "esbuild": "^0.25.1", "execa": "^9.6.0", "fast-json-patch": "^3.1.1", "fast-xml-parser": "^5.2.5", "find-process": "^2.0.0", "glob": "^10.0.0", "jszip": "^3.0.0", "libsodium-wrappers": "^0.7.15", "miniflare": "^4.20250906.0", "neverthrow": "^8.2.0", "open": "^10.1.2", "openapi-types": "^12.1.3", "pathe": "^2.0.3", "picocolors": "^1.1.1", "proper-lockfile": "^4.1.2", "signal-exit": "^4.1.0", "unenv": "2.0.0-rc.21", "ws": "^8.18.3", "yaml": "^2.0.0" }, "peerDependencies": { "@astrojs/cloudflare": "^12.6.4", "@aws-sdk/client-dynamodb": "^3.0.0", "@aws-sdk/client-iam": "^3.0.0", "@aws-sdk/client-lambda": "^3.0.0", "@aws-sdk/client-s3": "^3.0.0", "@aws-sdk/client-sesv2": "^3.0.0", "@aws-sdk/client-sqs": "^3.0.0", "@aws-sdk/client-ssm": "^3.0.0", "@aws-sdk/client-sts": "^3.0.0", "@cloudflare/vite-plugin": "^1.13.14", "@coinbase/cdp-sdk": "^0.10.0", "@libsql/client": "^0.15.12", "@opennextjs/cloudflare": "^1.6.5", "astro": "^5.13.2", "drizzle-orm": "^0.44.2", "rwsdk": "^0.1.36", "stripe": "^18.5.0", "vite": ">=6.0.0", "wrangler": "^4.42.2" }, "optionalPeers": ["@astrojs/cloudflare", "@aws-sdk/client-dynamodb", "@aws-sdk/client-iam", "@aws-sdk/client-lambda", "@aws-sdk/client-s3", "@aws-sdk/client-sesv2", "@aws-sdk/client-sqs", "@aws-sdk/client-ssm", "@aws-sdk/client-sts", "@cloudflare/vite-plugin", "@coinbase/cdp-sdk", "@libsql/client", "@opennextjs/cloudflare", "astro", "drizzle-orm", "rwsdk", "stripe", "vite"], "bin": { "alchemy": "bin/alchemy.js" } }, "sha512-/b/Sh9oWvfTVF6RkNU99qHj2ny5fkOGW1+I/4LvpO20Fc5hm0Gmo4mEcmaA1GJtYudj5mqypMvUC7RGNtcY9UQ=="], "ansi-align": ["[email protected]", "", { "dependencies": { "string-width": "^4.1.0" } }, "sha512-IOfwwBF5iczOjp/WeY4YxyjqAFMQoZufdQWDd19SEExbVLNXqvpzSJ/M7Za4/sCPmQ0+GRquoA7bGcINcxew6w=="], @@ -1952,8 +1914,6 @@ "arraybuffer.prototype.slice": ["[email protected]", "", { "dependencies": { "array-buffer-byte-length": "^1.0.1", "call-bind": "^1.0.8", "define-properties": "^1.2.1", "es-abstract": "^1.23.5", "es-errors": "^1.3.0", "get-intrinsic": "^1.2.6", "is-array-buffer": "^3.0.4" } }, "sha512-BNoCY6SXXPQ7gF2opIP4GBE+Xw7U+pHMYKuzjgCN3GwiaIR09UUeKfheyIry77QtrCBlC0KK0q5/TER/tYh3PQ=="], - "as-table": ["[email protected]", "", { "dependencies": { "printable-characters": "^1.0.42" } }, "sha512-xvsWESUJn0JN421Xb9MQw6AsMHRCUknCe0Wjlxvjud80mU4E6hQf1A6NzQKcYNmYw62MfzEtXc+badstZP3JpQ=="], - "assertion-error": ["[email protected]", "", {}, "sha512-Izi8RQcffqCeNVgFigKli1ssklIbpHnCYc6AknXGYoB6grJqyeby7jv12JUQgmTAnIDnbck1uxksT4dzN3PWBA=="], "ast-kit": ["[email protected]", "", { "dependencies": { "@babel/parser": "^7.28.5", "pathe": "^2.0.3" } }, "sha512-m1Q/RaVOnTp9JxPX+F+Zn7IcLYMzM8kZofDImfsKZd8MbR+ikdOzTeztStWqfrqIxZnYWryyI9ePm3NGjnZgGw=="], @@ -2464,7 +2424,7 @@ "entities": ["[email protected]", "", {}, "sha512-aN97NXWF6AWBTahfVOIrB/NShkzi5H7F9r1s9mD3cDj4Ko5f2qhhVoYMibXF7GlLveb/D2ioWay8lxI97Ven3g=="], - "env-paths": ["[email protected]", "", {}, "sha512-+h1lkLKhZMTYjog1VEpJNG7NZJWcuc2DDk/qsqSTRRCOXiLjeQ1d1/udrUGhqMxUgAlwKNZ0cf2uqan5GLuS2A=="], + "env-paths": ["[email protected]", "", {}, "sha512-dtJUTepzMW3Lm/NPxRf3wP4642UWhjL2sQxc+ym2YMj1m/H2zDNQOlezafzkHwn6sMstjHTwG6iQQsctDW/b1A=="], "environment": ["[email protected]", "", {}, "sha512-xUtoPkMggbz0MPyPiIWr1Kp4aeWJjDZ6SMvURhimjdZgsRuDplF5/s9hcgGhyXMhs+6vpnuoiZ2kFiu3FMnS8Q=="], @@ -2548,7 +2508,7 @@ "eventsource-parser": ["[email protected]", "", {}, "sha512-Vo1ab+QXPzZ4tCa8SwIHJFaSzy4R6SHf7BY79rFBDf0idraZWAkYrDjDj8uWaSm3S2TK+hJ7/t1CEmZ7jXw+pg=="], - "execa": ["[email protected]", "", { "dependencies": { "cross-spawn": "^7.0.3", "get-stream": "^6.0.0", "human-signals": "^2.1.0", "is-stream": "^2.0.0", "merge-stream": "^2.0.0", "npm-run-path": "^4.0.1", "onetime": "^5.1.2", "signal-exit": "^3.0.3", "strip-final-newline": "^2.0.0" } }, "sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg=="], + "execa": ["[email protected]", "", { "dependencies": { "@sindresorhus/merge-streams": "^4.0.0", "cross-spawn": "^7.0.6", "figures": "^6.1.0", "get-stream": "^9.0.0", "human-signals": "^8.0.1", "is-plain-obj": "^4.1.0", "is-stream": "^4.0.1", "npm-run-path": "^6.0.0", "pretty-ms": "^9.2.0", "signal-exit": "^4.1.0", "strip-final-newline": "^4.0.0", "yoctocolors": "^2.1.1" } }, "sha512-9Be3ZoN4LmYR90tUoVu2te2BsbzHfhJyfEiAVfz7N5/zv+jduIfLrV2xdQXOHbaD6KgpGdO9PRPM1Y4Q9QkPkA=="], "exit-hook": ["[email protected]", "", {}, "sha512-eNTPlAD67BmP31LDINZ3U7HSF8l57TxOY2PmBJ1shpCvpnxBF93mWCE8YHBnXs8qiUZJc9WDcWIeC3a2HIAMfw=="], @@ -2596,6 +2556,8 @@ "fflate": ["[email protected]", "", {}, "sha512-FJqqoDBR00Mdj9ppamLa/Y7vxm+PRmNWA67N846RvsoYVMKB4q3y/de5PA7gUmRMYK/8CMz2GDZQmCRN1wBcWA=="], + "figures": ["[email protected]", "", { "dependencies": { "is-unicode-supported": "^2.0.0" } }, "sha512-d+l3qxjSesT4V7v2fh+QnmFnUWv9lSpjarhShNTgBOfA0ttejbQUAlHLitbjkoRiDulW0OPoQPYIGhIC8ohejg=="], + "file-selector": ["[email protected]", "", { "dependencies": { "tslib": "^2.7.0" } }, "sha512-QgXo+mXTe8ljeqUFaX3QVHc5osSItJ/Km+xpocx0aSqWGMSCf6qYs/VnzZgS864Pjn5iceMRFigeAV7AfTlaig=="], "file-type": ["[email protected]", "", { "dependencies": { "@tokenizer/inflate": "^0.4.1", "strtok3": "^10.3.4", "token-types": "^6.1.1", "uint8array-extras": "^1.4.0" } }, "sha512-ifJXo8zUqbQ/bLbl9sFoqHNTNWbnPY1COImFfM6CCy7z+E+jC1eY9YfOKkx0fckIg+VljAy2/87T61fp0+eEkg=="], @@ -2606,6 +2568,8 @@ "finalhandler": ["[email protected]", "", { "dependencies": { "debug": "2.6.9", "encodeurl": "~2.0.0", "escape-html": "~1.0.3", "on-finished": "~2.4.1", "parseurl": "~1.3.3", "statuses": "~2.0.2", "unpipe": "~1.0.0" } }, "sha512-aA4RyPcd3badbdABGDuTXCMTtOneUCAYH/gxoYRTZlIJdF0YPWuGqiAsIrhNnnqdXGswYk6dGujem4w80UJFhg=="], + "find-process": ["[email protected]", "", { "dependencies": { "chalk": "~4.1.2", "commander": "^12.1.0", "loglevel": "^1.9.2" }, "bin": { "find-process": "dist/bin/find-process.js" } }, "sha512-YUBQnteWGASJoEVVsOXy6XtKAY2O1FCsWnnvQ8y0YwgY1rZiKeVptnFvMu6RSELZAJOGklqseTnUGGs5D0bKmg=="], + "find-up": ["[email protected]", "", { "dependencies": { "locate-path": "^6.0.0", "path-exists": "^4.0.0" } }, "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng=="], "firefox-profile": ["[email protected]", "", { "dependencies": { "adm-zip": "~0.5.x", "fs-extra": "^11.2.0", "ini": "^4.1.3", "minimist": "^1.2.8", "xml2js": "^0.6.2" }, "bin": { "firefox-profile": "lib/cli.js" } }, "sha512-aGApEu5bfCNbA4PGUZiRJAIU6jKmghV2UVdklXAofnNtiDjqYw0czLS46W7IfFqVKgKhFB8Ao2YoNGHY4BoIMQ=="], @@ -2676,9 +2640,7 @@ "get-proto": ["[email protected]", "", { "dependencies": { "dunder-proto": "^1.0.1", "es-object-atoms": "^1.0.0" } }, "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g=="], - "get-source": ["[email protected]", "", { "dependencies": { "data-uri-to-buffer": "^2.0.0", "source-map": "^0.6.1" } }, "sha512-X5+4+iD+HoSeEED+uwrQ07BOQr0kEDFMVqqpBuI+RaZBpBpHCuXxo70bjar6f0b0u/DQJsJ7ssurpP0V60Az+w=="], - - "get-stream": ["[email protected]", "", {}, "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg=="], + "get-stream": ["[email protected]", "", { "dependencies": { "@sec-ant/readable-stream": "^0.4.1", "is-stream": "^4.0.1" } }, "sha512-kVCxPF3vQM/N0B1PmoqVUqgHP+EeVjmZSQn+1oCRPxd2P21P2F19lIgbR3HBosbB1PUhOAoctJnfEn2GbN2eZA=="], "get-symbol-description": ["[email protected]", "", { "dependencies": { "call-bound": "^1.0.3", "es-errors": "^1.3.0", "get-intrinsic": "^1.2.6" } }, "sha512-w9UMqWwJxHNOvoNzSJ2oPF5wvYcvP7jUvYzhp67yEhTi17ZDBBC1z9pTdGuzjD+EFIqLSYRweZjqfiPzQ06Ebg=="], @@ -2810,7 +2772,7 @@ "https-proxy-agent": ["[email protected]", "", { "dependencies": { "agent-base": "6", "debug": "4" } }, "sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA=="], - "human-signals": ["[email protected]", "", {}, "sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw=="], + "human-signals": ["[email protected]", "", {}, "sha512-eKCa6bwnJhvxj14kZk5NCPc6Hb6BdsU9DZcOnmQKSnO1VKrfV0zCvtttPZUsBvjmNDn8rpcJfpwSYnHBjc95MQ=="], "humanize-ms": ["[email protected]", "", { "dependencies": { "ms": "^2.0.0" } }, "sha512-Fl70vYtsAFb/C06PTS9dZBo7ihau+Tu/DNCk/OyHhea07S+aeMWpFFkUaXRa8fI+ScZbEI8dfSxwY7gxZ9SAVQ=="], @@ -2946,7 +2908,7 @@ "is-shared-array-buffer": ["[email protected]", "", { "dependencies": { "call-bound": "^1.0.3" } }, "sha512-ISWac8drv4ZGfwKl5slpHG9OwPNty4jOWPRIhBpxOoD+hqITiwuipOQ2bNthAzwA3B4fIjO4Nln74N0S9byq8A=="], - "is-stream": ["[email protected]", "", {}, "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg=="], + "is-stream": ["[email protected]", "", {}, "sha512-Dnz92NInDqYckGEUJv689RbRiTSEHCQ7wOVeALbkOz999YpqT46yMRIGtSNl2iCL1waAZSx40+h59NV/EwzV/A=="], "is-string": ["[email protected]", "", { "dependencies": { "call-bound": "^1.0.3", "has-tostringtag": "^1.0.2" } }, "sha512-BtEeSsoaQjlSPBemMQIrY1MY0uM6vnS1g5fmufYOtnxLGUZM2178PKbhsk7Ffv58IX+ZtcvoGwccYsh0PglkAA=="], @@ -3036,7 +2998,7 @@ "khroma": ["[email protected]", "", {}, "sha512-Ls993zuzfayK269Svk9hzpeGUKob/sIgZzyHYdjQoAdQetRKpOLj+k/QQQ/6Qi0Yz65mlROrfd+Ev+1+7dz9Kw=="], - "kleur": ["[email protected]", "", {}, "sha512-o+NO+8WrRiQEE4/7nwRJhN1HWpVmJm511pBHUxPLtp0BUISzlBplORYSmTclCnJvQq2tKu/sgl3xVpkc7ZWuQQ=="], + "kleur": ["[email protected]", "", {}, "sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w=="], "ky": ["[email protected]", "", {}, "sha512-Rczb6FMM6JT0lvrOlP5WUOCB7s9XKxzwgErzhKlKde1bEV90FXplV1o87fpt4PU/asJFiqjYJxAJyzJhcrxOsQ=="], @@ -3114,6 +3076,8 @@ "log-update": ["[email protected]", "", { "dependencies": { "ansi-escapes": "^7.0.0", "cli-cursor": "^5.0.0", "slice-ansi": "^7.1.0", "strip-ansi": "^7.1.0", "wrap-ansi": "^9.0.0" } }, "sha512-9ie8ItPR6tjY5uYJh8K/Zrv/RMZ5VOlOWvtZdEHYSTFKZfIBPQa9tOAEeAWhd+AnIneLJ22w5fjOYtoutpWq5w=="], + "loglevel": ["[email protected]", "", {}, "sha512-HgMmCqIJSAKqo68l0rS2AanEWfkxaZ5wNiEFb5ggm08lDs9Xl2KxBlX3PTcaD2chBM1gXAYf491/M2Rv8Jwayg=="], + "longest-streak": ["[email protected]", "", {}, "sha512-9Ri+o0JYgehTaVBBDoMqIl8GXtbWg711O3srftcHhZ0dqnETqLaoIK0x17fUw9rFSlK/0NlsKe0Ahhyl5pXE2g=="], "loose-envify": ["[email protected]", "", { "dependencies": { "js-tokens": "^3.0.0 || ^4.0.0" }, "bin": { "loose-envify": "cli.js" } }, "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q=="], @@ -3292,7 +3256,7 @@ "mimic-response": ["[email protected]", "", {}, "sha512-e5ISH9xMYU0DzrT+jl8q2ze9D6eWBto+I8CNpe+VI+K2J/F/k3PdkdTdz4wvGVH4NTpo+NRYTVIuMQEMMcsLqg=="], - "miniflare": ["[email protected]", "", { "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": "^5.28.5", "workerd": "1.20250617.0", "ws": "8.18.0", "youch": "3.3.4", "zod": "3.22.3" }, "bin": { "miniflare": "bootstrap.js" } }, "sha512-IAoApFKxOJlaaFkym5ETstVX3qWzVt3xyqCDj6vSSTgEH3zxZJ5417jZGg8iQfMHosKCcQH1doPPqqnOZm/yrw=="], + "miniflare": ["[email protected]", "", { "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.14.0", "workerd": "1.20251202.0", "ws": "8.18.0", "youch": "4.1.0-beta.10", "zod": "3.22.3" }, "bin": { "miniflare": "bootstrap.js" } }, "sha512-cRp2QNgnt9wpLMoNs4MOzzomyfe9UTS9sPRxIpUvxMl+mweCZ0FHpWWQvCnU7wWlfAP8VGZrHwqSsV5ERA6ahQ=="], "minimatch": ["[email protected]", "", { "dependencies": { "brace-expansion": "^2.0.1" } }, "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow=="], @@ -3328,8 +3292,6 @@ "multimatch": ["[email protected]", "", { "dependencies": { "@types/minimatch": "^3.0.5", "array-differ": "^4.0.0", "array-union": "^3.0.1", "minimatch": "^3.0.4" } }, "sha512-I7tSVxHGPlmPN/enE3mS1aOSo6bWBfls+3HmuEeCUBCE7gWnm3cBXCBkpurzFjVRwC6Kld8lLaZ1Iv5vOcjvcQ=="], - "mustache": ["[email protected]", "", { "bin": { "mustache": "bin/mustache" } }, "sha512-71ippSywq5Yb7/tVYyGbkBggbU8H3u5Rz56fH60jGFgr8uHwxs+aSKeqmluIVzM0m0kB7xQjKS6qPfd0b2ZoqQ=="], - "mute-stream": ["[email protected]", "", {}, "sha512-WWdIxpyjEn+FhQJQQv9aQAYlHoNVdzIzUySNV1gHUPDSdZJ3yZn7pAAbQcV7B56Mvu881q9FZV+0Vx2xC44VWA=="], "mz": ["[email protected]", "", { "dependencies": { "any-promise": "^1.0.0", "object-assign": "^4.0.1", "thenify-all": "^1.0.0" } }, "sha512-z81GNO7nnYMEhrGh9LeymoE4+Yr0Wn5McHIZMK5cfQCl+NDX08sCZgUc9/6MHni9IWuFLm1Z3HTCXu2z9fN62Q=="], @@ -3376,7 +3338,7 @@ "normalize-url": ["[email protected]", "", {}, "sha512-X06Mfd/5aKsRHc0O0J5CUedwnPmnDtLF2+nq+KN9KSDlJHkPuh0JUviWjEWMe0SW/9TDdSLVPuk7L5gGTIA1/w=="], - "npm-run-path": ["[email protected]", "", { "dependencies": { "path-key": "^3.0.0" } }, "sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw=="], + "npm-run-path": ["[email protected]", "", { "dependencies": { "path-key": "^4.0.0", "unicorn-magic": "^0.3.0" } }, "sha512-9qny7Z9DsQU8Ou39ERsPU4OZQlSTP47ShQzuKZ6PRXpYLtIFgl/DEBYEXKlvcEa+9tHVcK8CF81Y2V72qaZhWA=="], "nth-check": ["[email protected]", "", { "dependencies": { "boolbase": "^1.0.0" } }, "sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w=="], @@ -3424,8 +3386,6 @@ "ora": ["[email protected]", "", { "dependencies": { "chalk": "^5.3.0", "cli-cursor": "^5.0.0", "cli-spinners": "^2.9.2", "is-interactive": "^2.0.0", "is-unicode-supported": "^2.0.0", "log-symbols": "^6.0.0", "stdin-discarder": "^0.2.2", "string-width": "^7.2.0", "strip-ansi": "^7.1.0" } }, "sha512-weP+BZ8MVNnlCm8c0Qdc1WSWq4Qn7I+9CJGm7Qali6g44e/PUzbjNqJX5NJ9ljlNMosfJvg1fKEGILklK9cwnw=="], - "os-paths": ["[email protected]", "", { "optionalDependencies": { "fsevents": "*" } }, "sha512-Ux1J4NUqC6tZayBqLN1kUlDAEvLiQlli/53sSddU4IN+h+3xxnv2HmRSMpVSvr1hvJzotfMs3ERvETGK+f4OwA=="], - "os-shim": ["[email protected]", "", {}, "sha512-jd0cvB8qQ5uVt0lvCIexBaROw1KyKm5sbulg2fWOHjETisuCzWyt+eTZKEMs8v6HwzoGs8xik26jg7eCM6pS+A=="], "own-keys": ["[email protected]", "", { "dependencies": { "get-intrinsic": "^1.2.6", "object-keys": "^1.1.1", "safe-push-apply": "^1.0.0" } }, "sha512-qFOyK5PjiWZd+QQIh+1jhdb9LpxTF0qs7Pm8o5QHYZ0M3vKqSqzsZaEB6oWlxZ+q2sJBMI/Ktgd2N5ZwQoRHfg=="], @@ -3464,6 +3424,8 @@ "parse-latin": ["[email protected]", "", { "dependencies": { "@types/nlcst": "^2.0.0", "@types/unist": "^3.0.0", "nlcst-to-string": "^4.0.0", "unist-util-modify-children": "^4.0.0", "unist-util-visit-children": "^3.0.0", "vfile": "^6.0.0" } }, "sha512-mhHgobPPua5kZ98EF4HWiH167JWBfl4pvAIXXdbaVohtK7a6YBOy56kvhCqduqyo/f3yrHFWmqmiMg/BkBkYYQ=="], + "parse-ms": ["[email protected]", "", {}, "sha512-TXfryirbmq34y8QBwgqCVLi+8oA3oWx2eAnSn62ITyEhEYaWRlVZ2DvMM9eZbMs/RfxPu/PK/aBLyGj4IrqMHw=="], + "parse-svg-path": ["[email protected]", "", {}, "sha512-JyPSBnkTJ0AI8GGJLfMXvKq42cj5c006fnLz6fXy6zfoVjJizi8BNTpu8on8ziI1cKy9d9DGNuY17Ce7wuejpQ=="], "parse5": ["[email protected]", "", { "dependencies": { "entities": "^6.0.0" } }, "sha512-IInvU7fabl34qmi9gY8XOVxhYyMyuH2xUNpb2q8/Y+7552KlejkRvqvD19nMoUW/uQGGbqNpA6Tufu5FL5BZgw=="], @@ -3568,7 +3530,7 @@ "prettier": ["[email protected]", "", { "bin": { "prettier": "bin/prettier.cjs" } }, "sha512-v6UNi1+3hSlVvv8fSaoUbggEM5VErKmmpGA7Pl3HF8V6uKY7rvClBOJlH6yNwQtfTueNkGVpOv/mtWL9L4bgRA=="], - "printable-characters": ["[email protected]", "", {}, "sha512-dKp+C4iXWK4vVYZmYSd0KBH5F/h1HoZRsbJ82AVKRO3PEo8L4lBS/vLwhVtpwwuYcoIsVY+1JYKR268yn480uQ=="], + "pretty-ms": ["[email protected]", "", { "dependencies": { "parse-ms": "^4.0.0" } }, "sha512-gjVS5hOP+M3wMm5nmNOucbIrqudzs9v/57bWRHQWLYklXqoXKrVfYW2W9+glfGsqtPgpiz5WwyEEB+ksXIx3gQ=="], "process-nextick-args": ["[email protected]", "", {}, "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag=="], @@ -3584,6 +3546,8 @@ "prop-types": ["[email protected]", "", { "dependencies": { "loose-envify": "^1.4.0", "object-assign": "^4.1.1", "react-is": "^16.13.1" } }, "sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg=="], + "proper-lockfile": ["[email protected]", "", { "dependencies": { "graceful-fs": "^4.2.4", "retry": "^0.12.0", "signal-exit": "^3.0.2" } }, "sha512-TjNPblN4BwAWMXU8s9AEz4JmQxnD1NNL7bNOY/AKUzyamc379FWASUhc/K1pL2noVb+XmZKLL68cjzLsiOAMaA=="], + "property-information": ["[email protected]", "", {}, "sha512-TwEZ+X+yCJmYfL7TPUOcvBZ4QfoT5YenQiJuX//0th53DE6w0xxLEtfK3iyryQFddXuvkIk51EEgrJQ0WJkOmQ=="], "proto-list": ["[email protected]", "", {}, "sha512-vtK/94akxsTMhe0/cbfpR+syPuszcuwhqVjJq26CuNDgFGj682oRBXOP5MJpv2r7JtE8MsiepGIqvvOTBwn2vA=="], @@ -3762,6 +3726,8 @@ "retext-stringify": ["[email protected]", "", { "dependencies": { "@types/nlcst": "^2.0.0", "nlcst-to-string": "^4.0.0", "unified": "^11.0.0" } }, "sha512-rtfN/0o8kL1e+78+uxPTqu1Klt0yPzKuQ2BfWwwfgIUSayyzxpM1PJzkKt4V8803uB9qSy32MvI7Xep9khTpiA=="], + "retry": ["[email protected]", "", {}, "sha512-9LkiTwjUh6rT555DtE9rTX+BKByPfrMzEAtnlEtdEwr3Nkffwiihqe2bWADg+OQRjt9gl6ICdmB/ZFDCGAtSow=="], + "reusify": ["[email protected]", "", {}, "sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw=="], "rfdc": ["[email protected]", "", {}, "sha512-q1b3N5QkRUWUl7iyylaaj3kOpIT0N2i9MqIEQXP73GVsN9cw3fdx8X63cEmWhJGi2PPCF23Ijp7ktmd39rawIA=="], @@ -3866,7 +3832,7 @@ "siginfo": ["[email protected]", "", {}, "sha512-ybx0WO1/8bSBLEWXZvEd7gMW3Sn3JFlW3TvX1nREbDLRNQNaeNN8WK0meBwPdAaOI7TtRRRJn/Es1zhrrCHu7g=="], - "signal-exit": ["[email protected]", "", {}, "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ=="], + "signal-exit": ["[email protected]", "", {}, "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw=="], "simple-eval": ["[email protected]", "", { "dependencies": { "jsep": "^1.3.6" } }, "sha512-LH7FpTAkeD+y5xQC4fzS+tFtaNlvt3Ib1zKzvhjv/Y+cioV4zIuw4IZr2yhRLu67CWL7FR9/6KXKnjRoZTvGGQ=="], @@ -3920,8 +3886,6 @@ "stacktrace-parser": ["[email protected]", "", { "dependencies": { "type-fest": "^0.7.1" } }, "sha512-WjlahMgHmCJpqzU8bIBy4qtsZdU9lRlcZE3Lvyej6t4tuOuv1vk57OW3MBrj6hXBFx/nNoC9MPMTcr5YA7NQbg=="], - "stacktracey": ["[email protected]", "", { "dependencies": { "as-table": "^1.0.36", "get-source": "^2.0.12" } }, "sha512-Kpij9riA+UNg7TnphqjH7/CzctQ/owJGNbFkfEeve4Z4uxT5+JapVLFXcsurIfN34gnTWZNJ/f7NMG0E8JDzTw=="], - "statuses": ["[email protected]", "", {}, "sha512-DvEy55V3DB7uknRo+4iOGT5fP1slR8wQohVdknigZPMpMstaKJQWhwiYBACJE3Ul2pTnATihhBYnRhZQHGBiRw=="], "std-env": ["[email protected]", "", {}, "sha512-5GS12FdOZNliM5mAOxFRg7Ir0pWz8MdpYm6AY6VPkGpbA7ZzmbzNcBJQ0GPvvyWgcY7QAhCgf9Uy89I03faLkg=="], @@ -3956,14 +3920,12 @@ "strip-bom": ["[email protected]", "", {}, "sha512-p+byADHF7SzEcVnLvc/r3uognM1hUhObuHXxJcgLCfD194XAkaLbjq3Wzb0N5G2tgIjH0dgT708Z51QxMeu60A=="], - "strip-final-newline": ["[email protected]", "", {}, "sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA=="], + "strip-final-newline": ["[email protected]", "", {}, "sha512-aulFJcD6YK8V1G7iRB5tigAP4TsHBZZrOV8pjV++zdUwmeV8uzbY7yn6h9MswN62adStNZFuCIx4haBnRuMDaw=="], "strip-json-comments": ["[email protected]", "", {}, "sha512-4X2FR3UwhNUE9G49aIsJW5hRRR3GXGTBTZRMfv568O60ojM8HcWjV/VxAxCDW3SUND33O6ZY66ZuRcdkj73q2g=="], "strip-literal": ["[email protected]", "", { "dependencies": { "js-tokens": "^9.0.1" } }, "sha512-8r3mkIM/2+PpjHoOtiAW8Rg3jJLHaV7xPwG+YRGrv6FP0wwk/toTpATxWYOW0BKdWwl82VT2tFYi5DlROa0Mxg=="], - "stripe": ["[email protected]", "", { "dependencies": { "@types/node": ">=8.1.0", "qs": "^6.11.0" } }, "sha512-aT2BU9KkizY9SATf14WhhYVv2uOapBWX0OFWF4xvcj1mPaNotlSc2CsxpS4DS46ZueSppmCF5BX1sNYBtwBvfw=="], - "strnum": ["[email protected]", "", {}, "sha512-7ZvoFTiCnGxBtDqJ//Cu6fWtZtc7Y3x+QOirG15wztbdngGSkht27o2pyGWrVy0b4WAy3jbKmnoK6g5VlVNUUw=="], "strtok3": ["[email protected]", "", { "dependencies": { "@tokenizer/token": "^0.3.0" } }, "sha512-KIy5nylvC5le1OdaaoCJ07L+8iQzJHGH6pWDuzS+d07Cu7n1MZ2x26P8ZKIWfbK02+XIL8Mp4RkWeqdUCrDMfg=="], @@ -3988,7 +3950,7 @@ "supermemory-browser-extension": ["supermemory-browser-extension@workspace:apps/browser-extension"], - "supports-color": ["[email protected]", "", {}, "sha512-SS+jx45GF1QjgEXQx4NJZV9ImqmO2NPz5FNsIHrsDjh2YsHnawpan7SNQ1o8NuhrbHZy9AZhIoCUiCeaW/C80g=="], + "supports-color": ["[email protected]", "", { "dependencies": { "has-flag": "^4.0.0" } }, "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw=="], "supports-preserve-symlinks-flag": ["[email protected]", "", {}, "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w=="], @@ -4128,11 +4090,13 @@ "unconfig-core": ["[email protected]", "", { "dependencies": { "@quansync/fs": "^1.0.0", "quansync": "^1.0.0" } }, "sha512-VgPCvLWugINbXvMQDf8Jh0mlbvNjNC6eSUziHsBCMpxR05OPrNrvDnyatdMjRgcHaaNsCqz+wjNXxNw1kRLHUg=="], - "undici": ["[email protected]", "", { "dependencies": { "@fastify/busboy": "^2.0.0" } }, "sha512-raqeBD6NQK4SkWhQzeYKd1KmIG6dllBOTt55Rmkt4HtI9mwdWtJljnrXjAFUBLTSN67HWrOIZ3EPF4kjUw80Bg=="], + "undici": ["[email protected]", "", {}, "sha512-Vqs8HTzjpQXZeXdpsfChQTlafcMQaaIwnGwLam1wudSSjlJeQ3bw1j+TLPePgrCnCpUXx7Ba5Pdpf5OBih62NQ=="], "undici-types": ["[email protected]", "", {}, "sha512-Zz+aZWSj8LE6zoxD+xrjh4VfkIG8Ya6LvYkZqtUQGJPZjYl53ypCaUwWqo7eI0x66KBGeRo+mlBEkMSeSZ38Nw=="], - "unenv": ["[email protected]", "", { "dependencies": { "defu": "^6.1.4", "exsolve": "^1.0.4", "ohash": "^2.0.11", "pathe": "^2.0.3", "ufo": "^1.6.1" } }, "sha512-B06u0wXkEd+o5gOCMl/ZHl5cfpYbDZKAT+HWTL+Hws6jWu7dCiqBBXXXzMFcFVJb8D4ytAnYmxJA83uwOQRSsg=="], + "unenv": ["[email protected]", "", { "dependencies": { "pathe": "^2.0.3" } }, "sha512-i7qRCmY42zmCwnYlh9H2SvLEypEFGye5iRmEMKjcGi7zk9UquigRjFtTLz0TYqr0ZGLZhaMHl/foy1bZR+Cwlw=="], + + "unicorn-magic": ["[email protected]", "", {}, "sha512-+QBBXBCvifc56fsbuxZQ6Sic3wqqc3WWaqxs58gvJrcOuN83HGTCwz3oS5phzU9LthRNE9VrJCFCLUgHeeFnfA=="], "unified": ["[email protected]", "", { "dependencies": { "@types/unist": "^3.0.0", "bail": "^2.0.0", "devlop": "^1.0.0", "extend": "^3.0.0", "is-plain-obj": "^4.0.0", "trough": "^2.0.0", "vfile": "^6.0.0" } }, "sha512-xKvGhPWw3k84Qjh8bI3ZeJjqnyadK+GEFtazSfZv/rKeTkTjOJho6mFqh2SM96iIcZokxiOpg78GazTSg8+KHA=="], @@ -4270,9 +4234,9 @@ "winreg": ["[email protected]", "", {}, "sha512-typ/+JRmi7RqP1NanzFULK36vczznSNN8kWVA9vIqXyv8GhghUlwhGp1Xj3Nms1FsPcNnsQrJOR10N58/nQ9hQ=="], - "workerd": ["[email protected]", "", { "optionalDependencies": { "@cloudflare/workerd-darwin-64": "1.20250617.0", "@cloudflare/workerd-darwin-arm64": "1.20250617.0", "@cloudflare/workerd-linux-64": "1.20250617.0", "@cloudflare/workerd-linux-arm64": "1.20250617.0", "@cloudflare/workerd-windows-64": "1.20250617.0" }, "bin": { "workerd": "bin/workerd" } }, "sha512-Uv6p0PYUHp/W/aWfUPLkZVAoAjapisM27JJlwcX9wCPTfCfnuegGOxFMvvlYpmNaX4YCwEdLCwuNn3xkpSkuZw=="], + "workerd": ["[email protected]", "", { "optionalDependencies": { "@cloudflare/workerd-darwin-64": "1.20251202.0", "@cloudflare/workerd-darwin-arm64": "1.20251202.0", "@cloudflare/workerd-linux-64": "1.20251202.0", "@cloudflare/workerd-linux-arm64": "1.20251202.0", "@cloudflare/workerd-windows-64": "1.20251202.0" }, "bin": { "workerd": "bin/workerd" } }, "sha512-p08YfrUMHkjCECNdT36r+6DpJIZX4kixbZ4n6GMUcLR5Gh18fakSCsiQrh72iOm4M9QHv/rM7P8YvCrUPWT5sg=="], - "wrangler": ["[email protected]", "", { "dependencies": { "@cloudflare/kv-asset-handler": "0.4.0", "@cloudflare/unenv-preset": "2.3.3", "blake3-wasm": "2.1.5", "esbuild": "0.25.4", "miniflare": "4.20250617.4", "path-to-regexp": "6.3.0", "unenv": "2.0.0-rc.17", "workerd": "1.20250617.0" }, "optionalDependencies": { "fsevents": "~2.3.2" }, "peerDependencies": { "@cloudflare/workers-types": "^4.20250617.0" }, "optionalPeers": ["@cloudflare/workers-types"], "bin": { "wrangler": "bin/wrangler.js", "wrangler2": "bin/wrangler.js" } }, "sha512-m8qVO3YxhUTII+4U889G/f5UuLSvMkUkCNatupV2f/SJ+iqaWtP1QbuQII8bs2J/O4rqxsz46Wu2S50u7tKB5Q=="], + "wrangler": ["[email protected]", "", { "dependencies": { "@cloudflare/kv-asset-handler": "0.4.1", "@cloudflare/unenv-preset": "2.7.13", "blake3-wasm": "2.1.5", "esbuild": "0.27.0", "miniflare": "4.20251202.1", "path-to-regexp": "6.3.0", "unenv": "2.0.0-rc.24", "workerd": "1.20251202.0" }, "optionalDependencies": { "fsevents": "~2.3.2" }, "peerDependencies": { "@cloudflare/workers-types": "^4.20251202.0" }, "optionalPeers": ["@cloudflare/workers-types"], "bin": { "wrangler": "bin/wrangler.js", "wrangler2": "bin/wrangler.js" } }, "sha512-/wvnHlRnlHsqaeIgGbmcEJE5NFYdTUWHCKow+U5Tv2XwQXI9vXUqBwCLAGy/BwqyS5nnycRt2kppqCzgHgyb7Q=="], "wrap-ansi": ["[email protected]", "", { "dependencies": { "ansi-styles": "^6.2.1", "string-width": "^7.0.0", "strip-ansi": "^7.1.0" } }, "sha512-42AtmgqjV+X1VpdOfyTGOYRi0/zsoLqtXQckTmqTeybT+BDIbM/Guxo7x3pE2vtpr1ok6xRqM9OpBe+Jyoqyww=="], @@ -4286,12 +4250,8 @@ "wxt": ["[email protected]", "", { "dependencies": { "@1natsu/wait-element": "^4.1.2", "@aklinker1/rollup-plugin-visualizer": "5.12.0", "@webext-core/fake-browser": "^1.3.2", "@webext-core/isolated-element": "^1.1.2", "@webext-core/match-patterns": "^1.0.3", "@wxt-dev/browser": "^0.1.4", "@wxt-dev/storage": "^1.0.0", "async-mutex": "^0.5.0", "c12": "^3.2.0", "cac": "^6.7.14", "chokidar": "^4.0.3", "ci-info": "^4.3.0", "consola": "^3.4.2", "defu": "^6.1.4", "dotenv": "^17.2.2", "dotenv-expand": "^12.0.3", "esbuild": "^0.25.0", "fast-glob": "^3.3.3", "filesize": "^11.0.2", "fs-extra": "^11.3.1", "get-port-please": "^3.2.0", "giget": "^1.2.3 || ^2.0.0", "hookable": "^5.5.3", "import-meta-resolve": "^4.2.0", "is-wsl": "^3.1.0", "json5": "^2.2.3", "jszip": "^3.10.1", "linkedom": "^0.18.12", "magicast": "^0.3.5", "minimatch": "^10.0.3", "nano-spawn": "^1.0.2", "normalize-path": "^3.0.0", "nypm": "^0.6.1", "ohash": "^2.0.11", "open": "^10.2.0", "ora": "^8.2.0", "perfect-debounce": "^2.0.0", "picocolors": "^1.1.1", "prompts": "^2.4.2", "publish-browser-extension": "^2.3.0 || ^3.0.2", "scule": "^1.3.0", "unimport": "^3.13.1 || ^4.0.0 || ^5.0.0", "vite": "^5.4.19 || ^6.3.4 || ^7.0.0", "vite-node": "^2.1.4 || ^3.1.2", "web-ext-run": "^0.2.4" }, "bin": { "wxt": "bin/wxt.mjs", "wxt-publish-extension": "bin/wxt-publish-extension.cjs" } }, "sha512-DqqHc/5COs8GR21ii99bANXf/mu6zuDpiXFV1YKNsqO5/PvkrCx5arY0aVPL5IATsuacAnNzdj4eMc1qbzS53Q=="], - "xdg-app-paths": ["[email protected]", "", { "dependencies": { "xdg-portable": "^10.6.0" }, "optionalDependencies": { "fsevents": "*" } }, "sha512-mgxlWVZw0TNWHoGmXq+NC3uhCIc55dDpAlDkMQUaIAcQzysb0kxctwv//fvuW61/nAAeUBJMQ8mnZjMmuYwOcQ=="], - "xdg-basedir": ["[email protected]", "", {}, "sha512-GCPAHLvrIH13+c0SuacwvRYj2SxJXQ4kaVTT5xgL3kPrz56XxkF21IGhjSE1+W0aw7gpBWRGXLCPnPby6lSpmQ=="], - "xdg-portable": ["[email protected]", "", { "dependencies": { "os-paths": "^7.4.0" }, "optionalDependencies": { "fsevents": "*" } }, "sha512-xrcqhWDvtZ7WLmt8G4f3hHy37iK7D2idtosRgkeiSPZEPmBShp0VfmRBLWAPC6zLF48APJ21yfea+RfQMF4/Aw=="], - "xml2js": ["[email protected]", "", { "dependencies": { "sax": ">=0.6.0", "xmlbuilder": "~11.0.0" } }, "sha512-T4rieHaC1EXcES0Kxxj4JWgaUQHDk+qwHcYOCFHfiwKz7tOVPLq7Hjq9dM1WCMhylqMEfP7hMcOIChvotiZegA=="], "xmlbuilder": ["[email protected]", "", {}, "sha512-fDlsI/kFEx7gLvbecc0/ohLG50fugQp8ryHzMTuW9vSa1GJ0XYWKnhsUx7oie3G98+r56aTQIUB4kht42R3JvA=="], @@ -4320,7 +4280,7 @@ "yoga-layout": ["[email protected]", "", {}, "sha512-0LPOt3AxKqMdFBZA3HBAt/t/8vIKq7VaQYbuA8WxCgung+p9TVyKRYdpvCb80HcdTN2NkbIKbhNwKUfm3tQywQ=="], - "youch": ["[email protected]", "", { "dependencies": { "cookie": "^0.7.1", "mustache": "^4.2.0", "stacktracey": "^2.1.8" } }, "sha512-UeVBXie8cA35DS6+nBkls68xaBBXCye0CNznrhszZjTbRVnJKQuNsyLKBTTL4ln1o1rh2PKtv35twV7irj5SEg=="], + "youch": ["[email protected]", "", { "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" } }, "sha512-rLfVLB4FgQneDr0dv1oddCVZmKjcJ6yX6mS4pU82Mq/Dt9a3cLZQ62pDBL4AUO+uVrCvtWz3ZFUL2HFAFJ/BXQ=="], "youch-core": ["[email protected]", "", { "dependencies": { "@poppinss/exception": "^1.2.2", "error-stack-parser-es": "^1.0.5" } }, "sha512-ho7XuGjLaJ2hWHoK8yFnsUGy2Y5uDpqSTq1FkHLK4/oqKtyUU1AFbOOxY4IpC9f0fTLjwYbslUz0Po5BpD1wrA=="], @@ -4454,10 +4414,14 @@ "@aws-sdk/client-cloudfront/@smithy/util-utf8": ["@smithy/[email protected]", "", { "dependencies": { "@smithy/util-buffer-from": "^2.2.0", "tslib": "^2.6.2" } }, "sha512-R8Rdn8Hy72KKcebgLiv8jQcQkXoLMOGGv5uI1/k0l+snqkOzQ1R0ChUBCxWMlBsFMekWjq0wRudIweFs7sKT5A=="], - "@aws-sdk/client-cloudfront/@smithy/util-waiter": ["@smithy/[email protected]", "", { "dependencies": { "@smithy/abort-controller": "^2.2.0", "@smithy/types": "^2.12.0", "tslib": "^2.6.2" } }, "sha512-IHk53BVw6MPMi2Gsn+hCng8rFA3ZmR3Rk7GllxDUW9qFJl/hiSvskn7XldkECapQVkIg/1dHpMAxI9xSTaLLSA=="], - "@aws-sdk/client-cloudfront/fast-xml-parser": ["[email protected]", "", { "dependencies": { "strnum": "^1.0.5" }, "bin": { "fxparser": "src/cli/cli.js" } }, "sha512-B9/wizE4WngqQftFPmdaMYlXoJlJOYxGQOanC77fq9k8+Z0v5dDSVh+3glErdIROP//s/jgb7ZuxKfB8nVyo0g=="], + "@aws-sdk/client-dynamodb/@smithy/util-waiter": ["@smithy/[email protected]", "", { "dependencies": { "@smithy/abort-controller": "^4.2.5", "@smithy/types": "^4.9.0", "tslib": "^2.6.2" } }, "sha512-Dbun99A3InifQdIrsXZ+QLcC0PGBPAdrl4cj1mTgJvyc9N2zf7QSxg8TBkzsCmGJdE3TLbO9ycwpY0EkWahQ/g=="], + + "@aws-sdk/client-lambda/@smithy/util-waiter": ["@smithy/[email protected]", "", { "dependencies": { "@smithy/abort-controller": "^4.2.5", "@smithy/types": "^4.9.0", "tslib": "^2.6.2" } }, "sha512-Dbun99A3InifQdIrsXZ+QLcC0PGBPAdrl4cj1mTgJvyc9N2zf7QSxg8TBkzsCmGJdE3TLbO9ycwpY0EkWahQ/g=="], + + "@aws-sdk/client-s3/@smithy/util-waiter": ["@smithy/[email protected]", "", { "dependencies": { "@smithy/abort-controller": "^4.2.5", "@smithy/types": "^4.9.0", "tslib": "^2.6.2" } }, "sha512-Dbun99A3InifQdIrsXZ+QLcC0PGBPAdrl4cj1mTgJvyc9N2zf7QSxg8TBkzsCmGJdE3TLbO9ycwpY0EkWahQ/g=="], + "@aws-sdk/client-sts/@aws-crypto/sha256-browser": ["@aws-crypto/[email protected]", "", { "dependencies": { "@aws-crypto/ie11-detection": "^3.0.0", "@aws-crypto/sha256-js": "^3.0.0", "@aws-crypto/supports-web-crypto": "^3.0.0", "@aws-crypto/util": "^3.0.0", "@aws-sdk/types": "^3.222.0", "@aws-sdk/util-locate-window": "^3.0.0", "@aws-sdk/util-utf8-browser": "^3.0.0", "tslib": "^1.11.1" } }, "sha512-8VLmW2B+gjFbU5uMeqtQM6Nj0/F1bro80xQXCW6CQBWgosFWXTx77aeOF5CAIAmbOK64SdMBJdNr6J41yP5mvQ=="], "@aws-sdk/client-sts/@aws-crypto/sha256-js": ["@aws-crypto/[email protected]", "", { "dependencies": { "@aws-crypto/util": "^3.0.0", "@aws-sdk/types": "^3.222.0", "tslib": "^1.11.1" } }, "sha512-PnNN7os0+yd1XvXAy23CFOmTbMaDxgxXtTKHybrJ39Y8kGzBATgBFibWJKH6BhytLI/Zyszs87xCOBNyBig6vQ=="], @@ -4568,14 +4532,14 @@ "@dotenvx/dotenvx/commander": ["[email protected]", "", {}, "sha512-yPVavfyCcRhmorC7rWlkHn15b4wDVgVmBA7kV4QVBsF7kv/9TKJAbAXVTxvTnwP8HHKjRCJDClKbciiYS7p0DQ=="], + "@dotenvx/dotenvx/execa": ["[email protected]", "", { "dependencies": { "cross-spawn": "^7.0.3", "get-stream": "^6.0.0", "human-signals": "^2.1.0", "is-stream": "^2.0.0", "merge-stream": "^2.0.0", "npm-run-path": "^4.0.1", "onetime": "^5.1.2", "signal-exit": "^3.0.3", "strip-final-newline": "^2.0.0" } }, "sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg=="], + "@dotenvx/dotenvx/which": ["[email protected]", "", { "dependencies": { "isexe": "^3.1.1" }, "bin": { "node-which": "bin/which.js" } }, "sha512-GlaYyEb07DPxYCKhKzplCWBJtvxZcZMrL+4UkrTSJHHPyZU4mYYTv3qaOe77H7EODLSSopAUFAc6W8U4yqvscg=="], "@ecies/ciphers/@noble/ciphers": ["@noble/[email protected]", "", {}, "sha512-2I0gnIVPtfnMw9ee9h1dJG7tp81+8Ob3OJb3Mv37rx5L40/b0i7djjCVvGOVqc9AEIQyvyu1i6ypKdFw8R8gQw=="], "@esbuild-kit/core-utils/esbuild": ["[email protected]", "", { "optionalDependencies": { "@esbuild/android-arm": "0.18.20", "@esbuild/android-arm64": "0.18.20", "@esbuild/android-x64": "0.18.20", "@esbuild/darwin-arm64": "0.18.20", "@esbuild/darwin-x64": "0.18.20", "@esbuild/freebsd-arm64": "0.18.20", "@esbuild/freebsd-x64": "0.18.20", "@esbuild/linux-arm": "0.18.20", "@esbuild/linux-arm64": "0.18.20", "@esbuild/linux-ia32": "0.18.20", "@esbuild/linux-loong64": "0.18.20", "@esbuild/linux-mips64el": "0.18.20", "@esbuild/linux-ppc64": "0.18.20", "@esbuild/linux-riscv64": "0.18.20", "@esbuild/linux-s390x": "0.18.20", "@esbuild/linux-x64": "0.18.20", "@esbuild/netbsd-x64": "0.18.20", "@esbuild/openbsd-x64": "0.18.20", "@esbuild/sunos-x64": "0.18.20", "@esbuild/win32-arm64": "0.18.20", "@esbuild/win32-ia32": "0.18.20", "@esbuild/win32-x64": "0.18.20" }, "bin": { "esbuild": "bin/esbuild" } }, "sha512-ceqxoedUrcayh7Y7ZX6NdbbDzGROiyVBgC4PriJThBKSVPWnnFHZAkfI1lJT8QFkOwH4qOS2SJkS4wvpGl8BpA=="], - "@inquirer/core/signal-exit": ["[email protected]", "", {}, "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw=="], - "@inquirer/core/wrap-ansi": ["[email protected]", "", { "dependencies": { "ansi-styles": "^4.0.0", "string-width": "^4.1.0", "strip-ansi": "^6.0.0" } }, "sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA=="], "@inquirer/external-editor/iconv-lite": ["[email protected]", "", { "dependencies": { "safer-buffer": ">= 2.1.2 < 3.0.0" } }, "sha512-cf6L2Ds3h57VVmkZe+Pn+5APsT7FpqJtEhhieDCvrE2MK5Qk9MyffgQyuxQTm6BChfeZNtcOLHp9IcWRVcIcBQ=="], @@ -4698,6 +4662,10 @@ "@pnpm/network.ca-file/graceful-fs": ["[email protected]", "", {}, "sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA=="], + "@poppinss/colors/kleur": ["[email protected]", "", {}, "sha512-o+NO+8WrRiQEE4/7nwRJhN1HWpVmJm511pBHUxPLtp0BUISzlBplORYSmTclCnJvQq2tKu/sgl3xVpkc7ZWuQQ=="], + + "@poppinss/dumper/supports-color": ["[email protected]", "", {}, "sha512-SS+jx45GF1QjgEXQx4NJZV9ImqmO2NPz5FNsIHrsDjh2YsHnawpan7SNQ1o8NuhrbHZy9AZhIoCUiCeaW/C80g=="], + "@puppeteer/browsers/yargs": ["[email protected]", "", { "dependencies": { "cliui": "^8.0.1", "escalade": "^3.1.1", "get-caller-file": "^2.0.5", "require-directory": "^2.1.1", "string-width": "^4.2.3", "y18n": "^5.0.5", "yargs-parser": "^21.1.1" } }, "sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w=="], "@radix-ui/react-alert-dialog/@radix-ui/react-slot": ["@radix-ui/[email protected]", "", { "dependencies": { "@radix-ui/react-compose-refs": "1.1.2" }, "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-aeNmHnBxbi2St0au6VBVC7JXFlhLlOnvIIlePNniyUNAClzmtAUEY8/pBiK3iHjufOlwA+c20/8jngo7xcrg8A=="], @@ -4740,8 +4708,6 @@ "@repo/web/typescript": ["[email protected]", "", { "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" } }, "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw=="], - "@repo/web/wrangler": ["[email protected]", "", { "dependencies": { "@cloudflare/kv-asset-handler": "0.4.1", "@cloudflare/unenv-preset": "2.7.13", "blake3-wasm": "2.1.5", "esbuild": "0.27.0", "miniflare": "4.20251202.1", "path-to-regexp": "6.3.0", "unenv": "2.0.0-rc.24", "workerd": "1.20251202.0" }, "optionalDependencies": { "fsevents": "~2.3.2" }, "peerDependencies": { "@cloudflare/workers-types": "^4.20251202.0" }, "optionalPeers": ["@cloudflare/workers-types"], "bin": { "wrangler": "bin/wrangler.js", "wrangler2": "bin/wrangler.js" } }, "sha512-/wvnHlRnlHsqaeIgGbmcEJE5NFYdTUWHCKow+U5Tv2XwQXI9vXUqBwCLAGy/BwqyS5nnycRt2kppqCzgHgyb7Q=="], - "@scalar/types/nanoid": ["[email protected]", "", { "bin": { "nanoid": "bin/nanoid.js" } }, "sha512-Ir/+ZpE9fDsNH0hQ3C68uyThDXzYcim2EqcZ8zn8Chtt1iylPT9xXJB0kPCnqzgcEGikO9RxSrh63MsmVCU7Fw=="], "@scalar/types/type-fest": ["[email protected]", "", { "dependencies": { "tagged-tag": "^1.0.0" } }, "sha512-GeJop7+u7BYlQ6yQCAY1nBQiRSHR+6OdCEtd8Bwp9a3NK3+fWAVjOaPKJDteB9f6cIJ0wt4IfnScjLG450EpXA=="], @@ -4752,6 +4718,10 @@ "@shikijs/core/hast-util-to-html": ["[email protected]", "", { "dependencies": { "@types/hast": "^3.0.0", "@types/unist": "^3.0.0", "ccount": "^2.0.0", "comma-separated-tokens": "^2.0.0", "hast-util-whitespace": "^3.0.0", "html-void-elements": "^3.0.0", "mdast-util-to-hast": "^13.0.0", "property-information": "^7.0.0", "space-separated-tokens": "^2.0.0", "stringify-entities": "^4.0.0", "zwitch": "^2.0.4" } }, "sha512-OguPdidb+fbHQSU4Q4ZiLKnzWo8Wwsf5bZfbvu7//a9oTYoqD/fWpe96NuHkoS9h0ccGOTe0C4NGXdtS0iObOw=="], + "@smithy/util-waiter/@smithy/abort-controller": ["@smithy/[email protected]", "", { "dependencies": { "@smithy/types": "^2.12.0", "tslib": "^2.6.2" } }, "sha512-wRlta7GuLWpTqtFfGo+nZyOO1vEvewdNR1R4rTxpC8XU6vG/NDyrFBhwLZsqg1NUoR1noVaXJPC/7ZK47QCySw=="], + + "@smithy/util-waiter/@smithy/types": ["@smithy/[email protected]", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-QwYgloJ0sVNBeBuBs65cIkTbfzV/Q6ZNPCJ99EICFEdJYG50nGIY/uYXp+TbsdJReIuPr0a0kXmCvren3MbRRw=="], + "@stoplight/better-ajv-errors/leven": ["[email protected]", "", {}, "sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A=="], "@stoplight/json/safe-stable-stringify": ["[email protected]", "", {}, "sha512-ERq4hUjKDbJfE4+XtZLFPCDi8Vb1JqaxAPTxWFLBx8XcAlf9Bda/ZJdVezs/NAfsMQScyIlUMx+Yeu7P7rx5jw=="], @@ -4820,11 +4790,9 @@ "ajv-keywords/fast-deep-equal": ["[email protected]", "", {}, "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q=="], - "alchemy/@cloudflare/unenv-preset": ["@cloudflare/[email protected]", "", { "peerDependencies": { "unenv": "2.0.0-rc.24", "workerd": "^1.20251202.0" }, "optionalPeers": ["workerd"] }, "sha512-NulO1H8R/DzsJguLC0ndMuk4Ufv0KSlN+E54ay9rn9ZCQo0kpAPwwh3LhgpZ96a3Dr6L9LqW57M4CqC34iLOvw=="], - - "alchemy/miniflare": ["[email protected]", "", { "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.14.0", "workerd": "1.20251202.0", "ws": "8.18.0", "youch": "4.1.0-beta.10", "zod": "3.22.3" }, "bin": { "miniflare": "bootstrap.js" } }, "sha512-cRp2QNgnt9wpLMoNs4MOzzomyfe9UTS9sPRxIpUvxMl+mweCZ0FHpWWQvCnU7wWlfAP8VGZrHwqSsV5ERA6ahQ=="], + "alchemy/@cloudflare/unenv-preset": ["@cloudflare/[email protected]", "", { "peerDependencies": { "unenv": "2.0.0-rc.21", "workerd": "^1.20250927.0" }, "optionalPeers": ["workerd"] }, "sha512-HtZuh166y0Olbj9bqqySckz0Rw9uHjggJeoGbDx5x+sgezBXlxO6tQSig2RZw5tgObF8mWI8zaPvQMkQZtAODw=="], - "alchemy/unenv": ["[email protected]", "", { "dependencies": { "defu": "^6.1.4", "exsolve": "^1.0.4", "ohash": "^2.0.11", "pathe": "^2.0.3", "ufo": "^1.5.4" } }, "sha512-J/rEIZU8w6FOfLNz/hNKsnY+fFHWnu9MH4yRbSZF3xbbGHovcetXPs7sD+9p8L6CeNC//I9bhRYAOsBt2u7/OA=="], + "alchemy/unenv": ["[email protected]", "", { "dependencies": { "defu": "^6.1.4", "exsolve": "^1.0.7", "ohash": "^2.0.11", "pathe": "^2.0.3", "ufo": "^1.6.1" } }, "sha512-Wj7/AMtE9MRnAXa6Su3Lk0LNCfqDYgfwVjwRFVum9U7wsto1imuHqk4kTm7Jni+5A0Hn7dttL6O/zjvUvoo+8A=="], "ansi-align/string-width": ["[email protected]", "", { "dependencies": { "emoji-regex": "^8.0.0", "is-fullwidth-code-point": "^3.0.0", "strip-ansi": "^6.0.1" } }, "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g=="], @@ -4846,6 +4814,8 @@ "c12/dotenv": ["[email protected]", "", {}, "sha512-JVUnt+DUIzu87TABbhPmNfVdBDt18BLOWjMUFJMSi/Qqg7NTYtabbvSNJGOJ7afbRuv9D/lngizHtP7QyLQ+9w=="], + "cacheable-request/get-stream": ["[email protected]", "", {}, "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg=="], + "chrome-launcher/escape-string-regexp": ["[email protected]", "", {}, "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA=="], "chrome-launcher/is-wsl": ["[email protected]", "", { "dependencies": { "is-docker": "^2.0.0" } }, "sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww=="], @@ -4864,6 +4834,8 @@ "config-chain/ini": ["[email protected]", "", {}, "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew=="], + "cosmiconfig/env-paths": ["[email protected]", "", {}, "sha512-+h1lkLKhZMTYjog1VEpJNG7NZJWcuc2DDk/qsqSTRRCOXiLjeQ1d1/udrUGhqMxUgAlwKNZ0cf2uqan5GLuS2A=="], + "cosmiconfig/js-yaml": ["[email protected]", "", { "dependencies": { "argparse": "^2.0.1" }, "bin": { "js-yaml": "bin/js-yaml.js" } }, "sha512-qQKT4zQxXl8lLwBtHMWwaTcGfFOZviOJet3Oy/xmGk2gZH677CJM9EvtfdSkgWcATZhj/55JZ0rmy3myCT5lsA=="], "cosmiconfig/parse-json": ["[email protected]", "", { "dependencies": { "@babel/code-frame": "^7.0.0", "error-ex": "^1.3.1", "json-parse-even-better-errors": "^2.3.0", "lines-and-columns": "^1.1.6" } }, "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg=="], @@ -4920,7 +4892,9 @@ "finalhandler/debug": ["[email protected]", "", { "dependencies": { "ms": "2.0.0" } }, "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA=="], - "foreground-child/signal-exit": ["[email protected]", "", {}, "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw=="], + "find-process/chalk": ["[email protected]", "", { "dependencies": { "ansi-styles": "^4.1.0", "supports-color": "^7.1.0" } }, "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA=="], + + "find-process/commander": ["[email protected]", "", {}, "sha512-Vw8qHK3bZM9y/P10u3Vib8o/DdkvA2OtPtZvD871QKjy74Wj1WSKFILMPRPSdUSx5RFK1arlJzEtA4PkFgnbuA=="], "front-matter/js-yaml": ["[email protected]", "", { "dependencies": { "argparse": "^1.0.7", "esprima": "^4.0.0" }, "bin": { "js-yaml": "bin/js-yaml.js" } }, "sha512-PMSmkqxr106Xa156c2M265Z+FTrPl+oxd/rgOQy2tijQeK5TxQ43psO1ZCwhVOSdnn+RzkzlRz/eY4BgJBYVpg=="], @@ -4934,8 +4908,6 @@ "gaxios/node-fetch": ["[email protected]", "", { "dependencies": { "data-uri-to-buffer": "^4.0.0", "fetch-blob": "^3.1.4", "formdata-polyfill": "^4.0.10" } }, "sha512-dRB78srN/l6gqWulah9SrxeYnxeddIG30+GOqK/9OlLVyLg3HPnr6SqOWTWOXKRwC2eGYCkZ59NNuSgvSrpgOA=="], - "get-source/data-uri-to-buffer": ["[email protected]", "", {}, "sha512-ND9qDTLc6diwj+Xe5cdAgVTbLVdXbtxTJRXRhli8Mowuaan+0EJOtdqJ0QCHNSSPyoXGx9HX2/VMnKeC34AChA=="], - "get-uri/data-uri-to-buffer": ["[email protected]", "", {}, "sha512-7hvf7/GW8e86rW0ptuwS3OcBGDjIi6SZva7hCyWC0yYry2cOPmLIjXAUHI6DK2HsnwJd9ifmt57i8eV2n4YNpw=="], "global-directory/ini": ["[email protected]", "", {}, "sha512-QQnnxNyfvmHFIsj7gkPcYymR8Jdw/o7mp5ZFihxn6h8Ci6fh3Dx4E1gPjpQEpIuPo9XVNY/ZUwh4BPMjGyL01g=="], @@ -4944,6 +4916,8 @@ "got/form-data-encoder": ["[email protected]", "", {}, "sha512-yDYSgNMraqvnxiEXO4hi88+YZxaHC6QKzb5N84iRCTDeRO7ZALpir/lVmf/uXUhnwUr2O4HU8s/n6x+yNjQkHw=="], + "got/get-stream": ["[email protected]", "", {}, "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg=="], + "hast-util-to-html/property-information": ["[email protected]", "", {}, "sha512-PgTgs/BlvHxOu8QuEN7wi5A0OmXaBcHpmCSTehcs6Uuu9IkDIEo13Hy7n898RHfrQ49vKCoGeWZSaAK01nwVig=="], "hast-util-to-mdast/hast-util-to-html": ["[email protected]", "", { "dependencies": { "@types/hast": "^3.0.0", "@types/unist": "^3.0.0", "ccount": "^2.0.0", "comma-separated-tokens": "^2.0.0", "hast-util-whitespace": "^3.0.0", "html-void-elements": "^3.0.0", "mdast-util-to-hast": "^13.0.0", "property-information": "^7.0.0", "space-separated-tokens": "^2.0.0", "stringify-entities": "^4.0.0", "zwitch": "^2.0.4" } }, "sha512-OguPdidb+fbHQSU4Q4ZiLKnzWo8Wwsf5bZfbvu7//a9oTYoqD/fWpe96NuHkoS9h0ccGOTe0C4NGXdtS0iObOw=="], @@ -4962,6 +4936,8 @@ "ink/react-reconciler": ["[email protected]", "", { "dependencies": { "scheduler": "^0.26.0" }, "peerDependencies": { "react": "^19.1.0" } }, "sha512-2NPMOzgTlG0ZWdIf3qG+dcbLSoAc/uLfOwckc3ofy5sSK0pLJqnQLpUFxvGcN2rlXSjnVtGeeFLNimCQEj5gOQ=="], + "ink/signal-exit": ["[email protected]", "", {}, "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ=="], + "is-online/got": ["[email protected]", "", { "dependencies": { "@sindresorhus/is": "^5.2.0", "@szmarczak/http-timer": "^5.0.1", "cacheable-lookup": "^7.0.0", "cacheable-request": "^10.2.8", "decompress-response": "^6.0.0", "form-data-encoder": "^2.1.2", "get-stream": "^6.0.1", "http2-wrapper": "^2.1.10", "lowercase-keys": "^3.0.0", "p-cancelable": "^3.0.0", "responselike": "^3.0.0" } }, "sha512-mThBblvlAF1d4O5oqyvN+ZxLAYwIJK7bpMxgYqPD9okW0C3qm5FFn7k811QrcuEBwaogR3ngOFoCfs6mRv7teQ=="], "jest-worker/supports-color": ["[email protected]", "", { "dependencies": { "has-flag": "^4.0.0" } }, "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q=="], @@ -5016,6 +4992,8 @@ "node-notifier/uuid": ["[email protected]", "", { "bin": { "uuid": "dist/bin/uuid" } }, "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg=="], + "npm-run-path/path-key": ["[email protected]", "", {}, "sha512-haREypq7xkM7ErfgIyA0z+Bj4AGKlMSdlQE2jvJo6huWD1EdkKYV+G/T4nq0YEF2vgTT8kqMFKo1uHn950r4SQ=="], + "openai/@types/node": ["@types/[email protected]", "", { "dependencies": { "undici-types": "~5.26.4" } }, "sha512-GRaXQx6jGfL8sKfaIDD6OupbIHBr9jv7Jnaml9tB7l4v068PAOXqfcujMMo5PhbIs6ggR1XODELqahT2R8v0fg=="], "pac-proxy-agent/agent-base": ["[email protected]", "", {}, "sha512-MnA+YT8fwfJPgBx3m60MNqakm30XOkyIoH1y6huTQvC0PwZG7ki8NacLBcrPbNoo8vEZy7Jpuk7+jMO+CUovTQ=="], @@ -5034,10 +5012,10 @@ "postcss-nested/postcss-selector-parser": ["[email protected]", "", { "dependencies": { "cssesc": "^3.0.0", "util-deprecate": "^1.0.2" } }, "sha512-Q8qQfPiZ+THO/3ZrOrO0cJJKfpYCagtMUkXbnEfmgUjwXg6z/WBeOyS9APBBPCTSiDV+s4SwQGu8yFsiMRIudg=="], - "prompts/kleur": ["[email protected]", "", {}, "sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w=="], - "prop-types/react-is": ["[email protected]", "", {}, "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ=="], + "proper-lockfile/signal-exit": ["[email protected]", "", {}, "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ=="], + "proxy-agent/agent-base": ["[email protected]", "", {}, "sha512-MnA+YT8fwfJPgBx3m60MNqakm30XOkyIoH1y6huTQvC0PwZG7ki8NacLBcrPbNoo8vEZy7Jpuk7+jMO+CUovTQ=="], "proxy-agent/https-proxy-agent": ["[email protected]", "", { "dependencies": { "agent-base": "^7.1.2", "debug": "4" } }, "sha512-vK9P5/iUfdl95AI+JVyUuIcVtd4ofvtrOr3HNtM2yxC9bnMbEdp3x01OhQNnjb8IJYi38VlTE3mBXwcfvywuSw=="], @@ -5066,8 +5044,6 @@ "restore-cursor/onetime": ["[email protected]", "", { "dependencies": { "mimic-function": "^5.0.0" } }, "sha512-VXJjc87FScF88uafS3JllDgvAm+c/Slfz06lorj2uAY34rlUu0Nt+v8wreiImcrgAjjIHp1rXpTDlLOGw29WwQ=="], - "restore-cursor/signal-exit": ["[email protected]", "", {}, "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw=="], - "rolldown/@rolldown/pluginutils": ["@rolldown/[email protected]", "", {}, "sha512-vENRlFU4YbrwVqNDZ7fLvy+JR1CRkyr01jhSiDpE1u6py3OMzQfztQU2jxykW3ALNxO4kSlqIDeYyD0Y9RcQeQ=="], "router/path-to-regexp": ["[email protected]", "", {}, "sha512-7jdwVIRtsP8MYpdXSwOS0YdD0Du+qOoF/AEPIt88PcCFrZCzx41oxku1jD88hZBwbNUIEfpqvuhjFaMAqMTWnA=="], @@ -5162,7 +5138,7 @@ "which-builtin-type/isarray": ["[email protected]", "", {}, "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw=="], - "wrangler/esbuild": ["[email protected]", "", { "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" }, "bin": { "esbuild": "bin/esbuild" } }, "sha512-8pgjLUcUjcgDg+2Q4NYXnPbo/vncAY4UmyaCm0jZevERqCHZIaWwdJHkf8XQtu4AxSKCdvrUbT0XUr1IdZzI8Q=="], + "wrangler/esbuild": ["[email protected]", "", { "optionalDependencies": { "@esbuild/aix-ppc64": "0.27.0", "@esbuild/android-arm": "0.27.0", "@esbuild/android-arm64": "0.27.0", "@esbuild/android-x64": "0.27.0", "@esbuild/darwin-arm64": "0.27.0", "@esbuild/darwin-x64": "0.27.0", "@esbuild/freebsd-arm64": "0.27.0", "@esbuild/freebsd-x64": "0.27.0", "@esbuild/linux-arm": "0.27.0", "@esbuild/linux-arm64": "0.27.0", "@esbuild/linux-ia32": "0.27.0", "@esbuild/linux-loong64": "0.27.0", "@esbuild/linux-mips64el": "0.27.0", "@esbuild/linux-ppc64": "0.27.0", "@esbuild/linux-riscv64": "0.27.0", "@esbuild/linux-s390x": "0.27.0", "@esbuild/linux-x64": "0.27.0", "@esbuild/netbsd-arm64": "0.27.0", "@esbuild/netbsd-x64": "0.27.0", "@esbuild/openbsd-arm64": "0.27.0", "@esbuild/openbsd-x64": "0.27.0", "@esbuild/openharmony-arm64": "0.27.0", "@esbuild/sunos-x64": "0.27.0", "@esbuild/win32-arm64": "0.27.0", "@esbuild/win32-ia32": "0.27.0", "@esbuild/win32-x64": "0.27.0" }, "bin": { "esbuild": "bin/esbuild" } }, "sha512-jd0f4NHbD6cALCyGElNpGAOtWxSq46l9X/sWB0Nzd5er4Kz2YTm+Vl0qKFT9KUJvD8+fiO8AvoHhFvEatfVixA=="], "wrap-ansi-cjs/ansi-styles": ["[email protected]", "", { "dependencies": { "color-convert": "^2.0.1" } }, "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg=="], @@ -5174,8 +5150,6 @@ "wxt/minimatch": ["[email protected]", "", { "dependencies": { "@isaacs/brace-expansion": "^5.0.0" } }, "sha512-enIvLvRAFZYXJzkCYG5RKmPfrFArdLv+R+lbQ53BmIMLIry74bjKzX6iHAm8WYamJkhSSEabrWN5D97XnKObjQ=="], - "youch/cookie": ["[email protected]", "", {}, "sha512-yki5XnKuf750l50uGTllt6kKILY4nQ1eNIQatoXEByZ5dWgnKqbnqmTrBE5B4N7lrMJKQ2ytWMiTO2o0v6Ew/w=="], - "@ai-sdk/react/@ai-sdk/provider-utils/@ai-sdk/provider": ["@ai-sdk/[email protected]", "", { "dependencies": { "json-schema": "^0.4.0" } }, "sha512-Z8SPncMtS3RsoXITmT7NVwrAq6M44dmw0DoUOYJqNNtCu8iMWuxB8Nxsoqpa0uEEy9R1V1ZThJAXTYgjTUxl3w=="], "@ai-sdk/react/ai/@ai-sdk/gateway": ["@ai-sdk/[email protected]", "", { "dependencies": { "@ai-sdk/provider": "2.0.0-beta.1", "@ai-sdk/provider-utils": "3.0.0-beta.5" }, "peerDependencies": { "zod": "^3.25.76 || ^4" } }, "sha512-v+LXXm8INLYAdxHnNMVAJ/B7k+Nejn5dCQMg/F8SRetB5dEQ4sbfimE+b6rawILJznnsy2fugUO1oFFXlUS5Yg=="], @@ -5282,8 +5256,6 @@ "@aws-sdk/client-cloudfront/@smithy/util-utf8/@smithy/util-buffer-from": ["@smithy/[email protected]", "", { "dependencies": { "@smithy/is-array-buffer": "^2.2.0", "tslib": "^2.6.2" } }, "sha512-IJdWBbTcMQ6DA0gdNhh/BwrLkDR+ADW5Kr1aZmd4k3DIF6ezMV4R2NIAmT08wQJ3yUK82thHWmC/TnK/wpMMIA=="], - "@aws-sdk/client-cloudfront/@smithy/util-waiter/@smithy/abort-controller": ["@smithy/[email protected]", "", { "dependencies": { "@smithy/types": "^2.12.0", "tslib": "^2.6.2" } }, "sha512-wRlta7GuLWpTqtFfGo+nZyOO1vEvewdNR1R4rTxpC8XU6vG/NDyrFBhwLZsqg1NUoR1noVaXJPC/7ZK47QCySw=="], - "@aws-sdk/client-cloudfront/fast-xml-parser/strnum": ["[email protected]", "", {}, "sha512-vrN+B7DBIoTTZjnPNewwhx6cBA/H+IS7rfW68n7XxC1y7uoiGQBxaKzqucGUgavX15dJgiGztLJ8vxuEzwqBdA=="], "@aws-sdk/client-sts/@aws-crypto/sha256-browser/@aws-crypto/supports-web-crypto": ["@aws-crypto/[email protected]", "", { "dependencies": { "tslib": "^1.11.1" } }, "sha512-06hBdMwUAb2WFTuGG73LSC0wfPu93xWwo5vL2et9eymgmu3Id5vFAHBbajVWiGhPO37qcsdCap/FqXvJGJWPIg=="], @@ -5380,6 +5352,18 @@ "@devicefarmer/adbkit/debug/ms": ["[email protected]", "", {}, "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA=="], + "@dotenvx/dotenvx/execa/get-stream": ["[email protected]", "", {}, "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg=="], + + "@dotenvx/dotenvx/execa/human-signals": ["[email protected]", "", {}, "sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw=="], + + "@dotenvx/dotenvx/execa/is-stream": ["[email protected]", "", {}, "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg=="], + + "@dotenvx/dotenvx/execa/npm-run-path": ["[email protected]", "", { "dependencies": { "path-key": "^3.0.0" } }, "sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw=="], + + "@dotenvx/dotenvx/execa/signal-exit": ["[email protected]", "", {}, "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ=="], + + "@dotenvx/dotenvx/execa/strip-final-newline": ["[email protected]", "", {}, "sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA=="], + "@dotenvx/dotenvx/which/isexe": ["[email protected]", "", {}, "sha512-LpB/54B+/2J5hqQ7imZHfdU31OlgQqx7ZicVlkm9kzg9/w8GKLEcFfJl/t7DCEDueOyBAD6zCCwTO6Fzs0NoEQ=="], "@esbuild-kit/core-utils/esbuild/@esbuild/android-arm": ["@esbuild/[email protected]", "", { "os": "android", "cpu": "arm" }, "sha512-fyi7TDI/ijKKNZTUJAQqiG5T7YjJXgnzkURqmGj13C6dCqckZBLdl4h7bkhHt/t0WP+zO9/zwroDvANaOqO5Sw=="], @@ -5654,18 +5638,6 @@ "@repo/web/ai/@ai-sdk/provider-utils": ["@ai-sdk/[email protected]", "", { "dependencies": { "@ai-sdk/provider": "2.0.0-beta.1", "@standard-schema/spec": "^1.0.0", "eventsource-parser": "^3.0.3", "zod-to-json-schema": "^3.24.1" }, "peerDependencies": { "zod": "^3.25.76 || ^4" } }, "sha512-4Dv/wiGZrvO6fI7P0yMLa4XZru0XW8LPibTObbkHBdweLUVGIze7aCfxxQeY44Uqcbl/h6/yBTkx2XmPtwf/Ow=="], - "@repo/web/wrangler/@cloudflare/kv-asset-handler": ["@cloudflare/[email protected]", "", { "dependencies": { "mime": "^3.0.0" } }, "sha512-Nu8ahitGFFJztxUml9oD/DLb7Z28C8cd8F46IVQ7y5Btz575pvMY8AqZsXkX7Gds29eCKdMgIHjIvzskHgPSFg=="], - - "@repo/web/wrangler/@cloudflare/unenv-preset": ["@cloudflare/[email protected]", "", { "peerDependencies": { "unenv": "2.0.0-rc.24", "workerd": "^1.20251202.0" }, "optionalPeers": ["workerd"] }, "sha512-NulO1H8R/DzsJguLC0ndMuk4Ufv0KSlN+E54ay9rn9ZCQo0kpAPwwh3LhgpZ96a3Dr6L9LqW57M4CqC34iLOvw=="], - - "@repo/web/wrangler/esbuild": ["[email protected]", "", { "optionalDependencies": { "@esbuild/aix-ppc64": "0.27.0", "@esbuild/android-arm": "0.27.0", "@esbuild/android-arm64": "0.27.0", "@esbuild/android-x64": "0.27.0", "@esbuild/darwin-arm64": "0.27.0", "@esbuild/darwin-x64": "0.27.0", "@esbuild/freebsd-arm64": "0.27.0", "@esbuild/freebsd-x64": "0.27.0", "@esbuild/linux-arm": "0.27.0", "@esbuild/linux-arm64": "0.27.0", "@esbuild/linux-ia32": "0.27.0", "@esbuild/linux-loong64": "0.27.0", "@esbuild/linux-mips64el": "0.27.0", "@esbuild/linux-ppc64": "0.27.0", "@esbuild/linux-riscv64": "0.27.0", "@esbuild/linux-s390x": "0.27.0", "@esbuild/linux-x64": "0.27.0", "@esbuild/netbsd-arm64": "0.27.0", "@esbuild/netbsd-x64": "0.27.0", "@esbuild/openbsd-arm64": "0.27.0", "@esbuild/openbsd-x64": "0.27.0", "@esbuild/openharmony-arm64": "0.27.0", "@esbuild/sunos-x64": "0.27.0", "@esbuild/win32-arm64": "0.27.0", "@esbuild/win32-ia32": "0.27.0", "@esbuild/win32-x64": "0.27.0" }, "bin": { "esbuild": "bin/esbuild" } }, "sha512-jd0f4NHbD6cALCyGElNpGAOtWxSq46l9X/sWB0Nzd5er4Kz2YTm+Vl0qKFT9KUJvD8+fiO8AvoHhFvEatfVixA=="], - - "@repo/web/wrangler/miniflare": ["[email protected]", "", { "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.14.0", "workerd": "1.20251202.0", "ws": "8.18.0", "youch": "4.1.0-beta.10", "zod": "3.22.3" }, "bin": { "miniflare": "bootstrap.js" } }, "sha512-cRp2QNgnt9wpLMoNs4MOzzomyfe9UTS9sPRxIpUvxMl+mweCZ0FHpWWQvCnU7wWlfAP8VGZrHwqSsV5ERA6ahQ=="], - - "@repo/web/wrangler/unenv": ["[email protected]", "", { "dependencies": { "pathe": "^2.0.3" } }, "sha512-i7qRCmY42zmCwnYlh9H2SvLEypEFGye5iRmEMKjcGi7zk9UquigRjFtTLz0TYqr0ZGLZhaMHl/foy1bZR+Cwlw=="], - - "@repo/web/wrangler/workerd": ["[email protected]", "", { "optionalDependencies": { "@cloudflare/workerd-darwin-64": "1.20251202.0", "@cloudflare/workerd-darwin-arm64": "1.20251202.0", "@cloudflare/workerd-linux-64": "1.20251202.0", "@cloudflare/workerd-linux-arm64": "1.20251202.0", "@cloudflare/workerd-windows-64": "1.20251202.0" }, "bin": { "workerd": "bin/workerd" } }, "sha512-p08YfrUMHkjCECNdT36r+6DpJIZX4kixbZ4n6GMUcLR5Gh18fakSCsiQrh72iOm4M9QHv/rM7P8YvCrUPWT5sg=="], - "@stoplight/spectral-core/minimatch/brace-expansion": ["[email protected]", "", { "dependencies": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" } }, "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg=="], "@supermemory/ai-sdk/ai/@ai-sdk/gateway": ["@ai-sdk/[email protected]", "", { "dependencies": { "@ai-sdk/provider": "2.0.0", "@ai-sdk/provider-utils": "3.0.19", "@vercel/oidc": "3.0.5" }, "peerDependencies": { "zod": "^3.25.76 || ^4.1.8" } }, "sha512-BwV7DU/lAm3Xn6iyyvZdWgVxgLu3SNXzl5y57gMvkW4nGhAOV5269IrJzQwGt03bb107sa6H6uJwWxc77zXoGA=="], @@ -5736,22 +5708,6 @@ "ai-gateway-provider/ai/@ai-sdk/react": ["@ai-sdk/[email protected]", "", { "dependencies": { "@ai-sdk/provider-utils": "2.2.8", "@ai-sdk/ui-utils": "1.2.11", "swr": "^2.2.5", "throttleit": "2.1.0" }, "peerDependencies": { "react": "^18 || ^19 || ^19.0.0-rc", "zod": "^3.23.8" }, "optionalPeers": ["zod"] }, "sha512-jK1IZZ22evPZoQW3vlkZ7wvjYGYF+tRBKXtrcolduIkQ/m/sOAVcVeVDUDvh1T91xCnWCdUGCPZg2avZ90mv3g=="], - "alchemy/@cloudflare/unenv-preset/unenv": ["[email protected]", "", { "dependencies": { "pathe": "^2.0.3" } }, "sha512-i7qRCmY42zmCwnYlh9H2SvLEypEFGye5iRmEMKjcGi7zk9UquigRjFtTLz0TYqr0ZGLZhaMHl/foy1bZR+Cwlw=="], - - "alchemy/@cloudflare/unenv-preset/workerd": ["[email protected]", "", { "optionalDependencies": { "@cloudflare/workerd-darwin-64": "1.20251202.0", "@cloudflare/workerd-darwin-arm64": "1.20251202.0", "@cloudflare/workerd-linux-64": "1.20251202.0", "@cloudflare/workerd-linux-arm64": "1.20251202.0", "@cloudflare/workerd-windows-64": "1.20251202.0" }, "bin": { "workerd": "bin/workerd" } }, "sha512-p08YfrUMHkjCECNdT36r+6DpJIZX4kixbZ4n6GMUcLR5Gh18fakSCsiQrh72iOm4M9QHv/rM7P8YvCrUPWT5sg=="], - - "alchemy/miniflare/sharp": ["[email protected]", "", { "dependencies": { "color": "^4.2.3", "detect-libc": "^2.0.3", "semver": "^7.6.3" }, "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" } }, "sha512-haPVm1EkS9pgvHrQ/F3Xy+hgcuMV0Wm9vfIBSiwZ05k+xgb0PkBQpGsAA/oWdDobNaZTH5ppvHtzCFbnSEwHVw=="], - - "alchemy/miniflare/undici": ["[email protected]", "", {}, "sha512-Vqs8HTzjpQXZeXdpsfChQTlafcMQaaIwnGwLam1wudSSjlJeQ3bw1j+TLPePgrCnCpUXx7Ba5Pdpf5OBih62NQ=="], - - "alchemy/miniflare/workerd": ["[email protected]", "", { "optionalDependencies": { "@cloudflare/workerd-darwin-64": "1.20251202.0", "@cloudflare/workerd-darwin-arm64": "1.20251202.0", "@cloudflare/workerd-linux-64": "1.20251202.0", "@cloudflare/workerd-linux-arm64": "1.20251202.0", "@cloudflare/workerd-windows-64": "1.20251202.0" }, "bin": { "workerd": "bin/workerd" } }, "sha512-p08YfrUMHkjCECNdT36r+6DpJIZX4kixbZ4n6GMUcLR5Gh18fakSCsiQrh72iOm4M9QHv/rM7P8YvCrUPWT5sg=="], - - "alchemy/miniflare/ws": ["[email protected]", "", { "peerDependencies": { "bufferutil": "^4.0.1", "utf-8-validate": ">=5.0.2" }, "optionalPeers": ["bufferutil", "utf-8-validate"] }, "sha512-8VbfWfHLbbwu3+N6OKsOMpBdT4kXPDDB9cJk2bJ6mh9ucxdlnNvH1e+roYkKmN9Nxw2yjz7VzeO9oOz2zJ04Pw=="], - - "alchemy/miniflare/youch": ["[email protected]", "", { "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" } }, "sha512-rLfVLB4FgQneDr0dv1oddCVZmKjcJ6yX6mS4pU82Mq/Dt9a3cLZQ62pDBL4AUO+uVrCvtWz3ZFUL2HFAFJ/BXQ=="], - - "alchemy/miniflare/zod": ["[email protected]", "", {}, "sha512-EjIevzuJRiRPbVH4mGc8nApb/lVLKVpmUhAaR5R5doKGfAnGJ6Gr3CViAVjP+4FWSxCsybeWQdcgCtbX+7oZug=="], - "ansi-align/string-width/emoji-regex": ["[email protected]", "", {}, "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A=="], "ansi-align/string-width/strip-ansi": ["[email protected]", "", { "dependencies": { "ansi-regex": "^5.0.1" } }, "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A=="], @@ -5826,6 +5782,8 @@ "finalhandler/debug/ms": ["[email protected]", "", {}, "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A=="], + "find-process/chalk/ansi-styles": ["[email protected]", "", { "dependencies": { "color-convert": "^2.0.1" } }, "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg=="], + "front-matter/js-yaml/argparse": ["[email protected]", "", { "dependencies": { "sprintf-js": "~1.0.2" } }, "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg=="], "fx-runner/which/isexe": ["[email protected]", "", {}, "sha512-d2eJzK691yZwPHcv1LbeAOa91yMJ9QmfTgSO1oXB65ezVhXQsxBac2vEB4bMVms9cGzaA99n6V2viHMq82VLDw=="], @@ -5842,6 +5800,8 @@ "is-online/got/form-data-encoder": ["[email protected]", "", {}, "sha512-yDYSgNMraqvnxiEXO4hi88+YZxaHC6QKzb5N84iRCTDeRO7ZALpir/lVmf/uXUhnwUr2O4HU8s/n6x+yNjQkHw=="], + "is-online/got/get-stream": ["[email protected]", "", {}, "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg=="], + "memory-graph-playground/@types/node/undici-types": ["[email protected]", "", {}, "sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ=="], "memory-graph-playground/next/@next/env": ["@next/[email protected]", "", {}, "sha512-IqgtY5Vwsm14mm/nmQaRMmywCU+yyMIYfk3/MHZ2ZTJvwVbBn3usZnjMi1GacrMVzVcAxJShTCpZlPs26EdEjQ=="], @@ -5918,6 +5878,8 @@ "public-ip/got/form-data-encoder": ["[email protected]", "", {}, "sha512-yDYSgNMraqvnxiEXO4hi88+YZxaHC6QKzb5N84iRCTDeRO7ZALpir/lVmf/uXUhnwUr2O4HU8s/n6x+yNjQkHw=="], + "public-ip/got/get-stream": ["[email protected]", "", {}, "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg=="], + "send/debug/ms": ["[email protected]", "", {}, "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A=="], "serve-static/send/debug": ["[email protected]", "", { "dependencies": { "ms": "2.0.0" } }, "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA=="], @@ -5948,55 +5910,57 @@ "unplugin/chokidar/readdirp": ["[email protected]", "", { "dependencies": { "picomatch": "^2.2.1" } }, "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA=="], - "wrangler/esbuild/@esbuild/aix-ppc64": ["@esbuild/[email protected]", "", { "os": "aix", "cpu": "ppc64" }, "sha512-1VCICWypeQKhVbE9oW/sJaAmjLxhVqacdkvPLEjwlttjfwENRSClS8EjBz0KzRyFSCPDIkuXW34Je/vk7zdB7Q=="], + "wrangler/esbuild/@esbuild/aix-ppc64": ["@esbuild/[email protected]", "", { "os": "aix", "cpu": "ppc64" }, "sha512-KuZrd2hRjz01y5JK9mEBSD3Vj3mbCvemhT466rSuJYeE/hjuBrHfjjcjMdTm/sz7au+++sdbJZJmuBwQLuw68A=="], - "wrangler/esbuild/@esbuild/android-arm": ["@esbuild/[email protected]", "", { "os": "android", "cpu": "arm" }, "sha512-QNdQEps7DfFwE3hXiU4BZeOV68HHzYwGd0Nthhd3uCkkEKK7/R6MTgM0P7H7FAs5pU/DIWsviMmEGxEoxIZ+ZQ=="], + "wrangler/esbuild/@esbuild/android-arm": ["@esbuild/[email protected]", "", { "os": "android", "cpu": "arm" }, "sha512-j67aezrPNYWJEOHUNLPj9maeJte7uSMM6gMoxfPC9hOg8N02JuQi/T7ewumf4tNvJadFkvLZMlAq73b9uwdMyQ=="], - "wrangler/esbuild/@esbuild/android-arm64": ["@esbuild/[email protected]", "", { "os": "android", "cpu": "arm64" }, "sha512-bBy69pgfhMGtCnwpC/x5QhfxAz/cBgQ9enbtwjf6V9lnPI/hMyT9iWpR1arm0l3kttTr4L0KSLpKmLp/ilKS9A=="], + "wrangler/esbuild/@esbuild/android-arm64": ["@esbuild/[email protected]", "", { "os": "android", "cpu": "arm64" }, "sha512-CC3vt4+1xZrs97/PKDkl0yN7w8edvU2vZvAFGD16n9F0Cvniy5qvzRXjfO1l94efczkkQE6g1x0i73Qf5uthOQ=="], - "wrangler/esbuild/@esbuild/android-x64": ["@esbuild/[email protected]", "", { "os": "android", "cpu": "x64" }, "sha512-TVhdVtQIFuVpIIR282btcGC2oGQoSfZfmBdTip2anCaVYcqWlZXGcdcKIUklfX2wj0JklNYgz39OBqh2cqXvcQ=="], + "wrangler/esbuild/@esbuild/android-x64": ["@esbuild/[email protected]", "", { "os": "android", "cpu": "x64" }, "sha512-wurMkF1nmQajBO1+0CJmcN17U4BP6GqNSROP8t0X/Jiw2ltYGLHpEksp9MpoBqkrFR3kv2/te6Sha26k3+yZ9Q=="], - "wrangler/esbuild/@esbuild/darwin-arm64": ["@esbuild/[email protected]", "", { "os": "darwin", "cpu": "arm64" }, "sha512-Y1giCfM4nlHDWEfSckMzeWNdQS31BQGs9/rouw6Ub91tkK79aIMTH3q9xHvzH8d0wDru5Ci0kWB8b3up/nl16g=="], + "wrangler/esbuild/@esbuild/darwin-arm64": ["@esbuild/[email protected]", "", { "os": "darwin", "cpu": "arm64" }, "sha512-uJOQKYCcHhg07DL7i8MzjvS2LaP7W7Pn/7uA0B5S1EnqAirJtbyw4yC5jQ5qcFjHK9l6o/MX9QisBg12kNkdHg=="], - "wrangler/esbuild/@esbuild/darwin-x64": ["@esbuild/[email protected]", "", { "os": "darwin", "cpu": "x64" }, "sha512-CJsry8ZGM5VFVeyUYB3cdKpd/H69PYez4eJh1W/t38vzutdjEjtP7hB6eLKBoOdxcAlCtEYHzQ/PJ/oU9I4u0A=="], + "wrangler/esbuild/@esbuild/darwin-x64": ["@esbuild/[email protected]", "", { "os": "darwin", "cpu": "x64" }, "sha512-8mG6arH3yB/4ZXiEnXof5MK72dE6zM9cDvUcPtxhUZsDjESl9JipZYW60C3JGreKCEP+p8P/72r69m4AZGJd5g=="], - "wrangler/esbuild/@esbuild/freebsd-arm64": ["@esbuild/[email protected]", "", { "os": "freebsd", "cpu": "arm64" }, "sha512-yYq+39NlTRzU2XmoPW4l5Ifpl9fqSk0nAJYM/V/WUGPEFfek1epLHJIkTQM6bBs1swApjO5nWgvr843g6TjxuQ=="], + "wrangler/esbuild/@esbuild/freebsd-arm64": ["@esbuild/[email protected]", "", { "os": "freebsd", "cpu": "arm64" }, "sha512-9FHtyO988CwNMMOE3YIeci+UV+x5Zy8fI2qHNpsEtSF83YPBmE8UWmfYAQg6Ux7Gsmd4FejZqnEUZCMGaNQHQw=="], - "wrangler/esbuild/@esbuild/freebsd-x64": ["@esbuild/[email protected]", "", { "os": "freebsd", "cpu": "x64" }, "sha512-0FgvOJ6UUMflsHSPLzdfDnnBBVoCDtBTVyn/MrWloUNvq/5SFmh13l3dvgRPkDihRxb77Y17MbqbCAa2strMQQ=="], + "wrangler/esbuild/@esbuild/freebsd-x64": ["@esbuild/[email protected]", "", { "os": "freebsd", "cpu": "x64" }, "sha512-zCMeMXI4HS/tXvJz8vWGexpZj2YVtRAihHLk1imZj4efx1BQzN76YFeKqlDr3bUWI26wHwLWPd3rwh6pe4EV7g=="], - "wrangler/esbuild/@esbuild/linux-arm": ["@esbuild/[email protected]", "", { "os": "linux", "cpu": "arm" }, "sha512-kro4c0P85GMfFYqW4TWOpvmF8rFShbWGnrLqlzp4X1TNWjRY3JMYUfDCtOxPKOIY8B0WC8HN51hGP4I4hz4AaQ=="], + "wrangler/esbuild/@esbuild/linux-arm": ["@esbuild/[email protected]", "", { "os": "linux", "cpu": "arm" }, "sha512-t76XLQDpxgmq2cNXKTVEB7O7YMb42atj2Re2Haf45HkaUpjM2J0UuJZDuaGbPbamzZ7bawyGFUkodL+zcE+jvQ=="], - "wrangler/esbuild/@esbuild/linux-arm64": ["@esbuild/[email protected]", "", { "os": "linux", "cpu": "arm64" }, "sha512-+89UsQTfXdmjIvZS6nUnOOLoXnkUTB9hR5QAeLrQdzOSWZvNSAXAtcRDHWtqAUtAmv7ZM1WPOOeSxDzzzMogiQ=="], + "wrangler/esbuild/@esbuild/linux-arm64": ["@esbuild/[email protected]", "", { "os": "linux", "cpu": "arm64" }, "sha512-AS18v0V+vZiLJyi/4LphvBE+OIX682Pu7ZYNsdUHyUKSoRwdnOsMf6FDekwoAFKej14WAkOef3zAORJgAtXnlQ=="], - "wrangler/esbuild/@esbuild/linux-ia32": ["@esbuild/[email protected]", "", { "os": "linux", "cpu": "ia32" }, "sha512-yTEjoapy8UP3rv8dB0ip3AfMpRbyhSN3+hY8mo/i4QXFeDxmiYbEKp3ZRjBKcOP862Ua4b1PDfwlvbuwY7hIGQ=="], + "wrangler/esbuild/@esbuild/linux-ia32": ["@esbuild/[email protected]", "", { "os": "linux", "cpu": "ia32" }, "sha512-Mz1jxqm/kfgKkc/KLHC5qIujMvnnarD9ra1cEcrs7qshTUSksPihGrWHVG5+osAIQ68577Zpww7SGapmzSt4Nw=="], - "wrangler/esbuild/@esbuild/linux-loong64": ["@esbuild/[email protected]", "", { "os": "linux", "cpu": "none" }, "sha512-NeqqYkrcGzFwi6CGRGNMOjWGGSYOpqwCjS9fvaUlX5s3zwOtn1qwg1s2iE2svBe4Q/YOG1q6875lcAoQK/F4VA=="], + "wrangler/esbuild/@esbuild/linux-loong64": ["@esbuild/[email protected]", "", { "os": "linux", "cpu": "none" }, "sha512-QbEREjdJeIreIAbdG2hLU1yXm1uu+LTdzoq1KCo4G4pFOLlvIspBm36QrQOar9LFduavoWX2msNFAAAY9j4BDg=="], - "wrangler/esbuild/@esbuild/linux-mips64el": ["@esbuild/[email protected]", "", { "os": "linux", "cpu": "none" }, "sha512-IcvTlF9dtLrfL/M8WgNI/qJYBENP3ekgsHbYUIzEzq5XJzzVEV/fXY9WFPfEEXmu3ck2qJP8LG/p3Q8f7Zc2Xg=="], + "wrangler/esbuild/@esbuild/linux-mips64el": ["@esbuild/[email protected]", "", { "os": "linux", "cpu": "none" }, "sha512-sJz3zRNe4tO2wxvDpH/HYJilb6+2YJxo/ZNbVdtFiKDufzWq4JmKAiHy9iGoLjAV7r/W32VgaHGkk35cUXlNOg=="], - "wrangler/esbuild/@esbuild/linux-ppc64": ["@esbuild/[email protected]", "", { "os": "linux", "cpu": "ppc64" }, "sha512-HOy0aLTJTVtoTeGZh4HSXaO6M95qu4k5lJcH4gxv56iaycfz1S8GO/5Jh6X4Y1YiI0h7cRyLi+HixMR+88swag=="], + "wrangler/esbuild/@esbuild/linux-ppc64": ["@esbuild/[email protected]", "", { "os": "linux", "cpu": "ppc64" }, "sha512-z9N10FBD0DCS2dmSABDBb5TLAyF1/ydVb+N4pi88T45efQ/w4ohr/F/QYCkxDPnkhkp6AIpIcQKQ8F0ANoA2JA=="], - "wrangler/esbuild/@esbuild/linux-riscv64": ["@esbuild/[email protected]", "", { "os": "linux", "cpu": "none" }, "sha512-i8JUDAufpz9jOzo4yIShCTcXzS07vEgWzyX3NH2G7LEFVgrLEhjwL3ajFE4fZI3I4ZgiM7JH3GQ7ReObROvSUA=="], + "wrangler/esbuild/@esbuild/linux-riscv64": ["@esbuild/[email protected]", "", { "os": "linux", "cpu": "none" }, "sha512-pQdyAIZ0BWIC5GyvVFn5awDiO14TkT/19FTmFcPdDec94KJ1uZcmFs21Fo8auMXzD4Tt+diXu1LW1gHus9fhFQ=="], - "wrangler/esbuild/@esbuild/linux-s390x": ["@esbuild/[email protected]", "", { "os": "linux", "cpu": "s390x" }, "sha512-jFnu+6UbLlzIjPQpWCNh5QtrcNfMLjgIavnwPQAfoGx4q17ocOU9MsQ2QVvFxwQoWpZT8DvTLooTvmOQXkO51g=="], + "wrangler/esbuild/@esbuild/linux-s390x": ["@esbuild/[email protected]", "", { "os": "linux", "cpu": "s390x" }, "sha512-hPlRWR4eIDDEci953RI1BLZitgi5uqcsjKMxwYfmi4LcwyWo2IcRP+lThVnKjNtk90pLS8nKdroXYOqW+QQH+w=="], - "wrangler/esbuild/@esbuild/linux-x64": ["@esbuild/[email protected]", "", { "os": "linux", "cpu": "x64" }, "sha512-6e0cvXwzOnVWJHq+mskP8DNSrKBr1bULBvnFLpc1KY+d+irZSgZ02TGse5FsafKS5jg2e4pbvK6TPXaF/A6+CA=="], + "wrangler/esbuild/@esbuild/linux-x64": ["@esbuild/[email protected]", "", { "os": "linux", "cpu": "x64" }, "sha512-1hBWx4OUJE2cab++aVZ7pObD6s+DK4mPGpemtnAORBvb5l/g5xFGk0vc0PjSkrDs0XaXj9yyob3d14XqvnQ4gw=="], - "wrangler/esbuild/@esbuild/netbsd-arm64": ["@esbuild/[email protected]", "", { "os": "none", "cpu": "arm64" }, "sha512-vUnkBYxZW4hL/ie91hSqaSNjulOnYXE1VSLusnvHg2u3jewJBz3YzB9+oCw8DABeVqZGg94t9tyZFoHma8gWZQ=="], + "wrangler/esbuild/@esbuild/netbsd-arm64": ["@esbuild/[email protected]", "", { "os": "none", "cpu": "arm64" }, "sha512-6m0sfQfxfQfy1qRuecMkJlf1cIzTOgyaeXaiVaaki8/v+WB+U4hc6ik15ZW6TAllRlg/WuQXxWj1jx6C+dfy3w=="], - "wrangler/esbuild/@esbuild/netbsd-x64": ["@esbuild/[email protected]", "", { "os": "none", "cpu": "x64" }, "sha512-XAg8pIQn5CzhOB8odIcAm42QsOfa98SBeKUdo4xa8OvX8LbMZqEtgeWE9P/Wxt7MlG2QqvjGths+nq48TrUiKw=="], + "wrangler/esbuild/@esbuild/netbsd-x64": ["@esbuild/[email protected]", "", { "os": "none", "cpu": "x64" }, "sha512-xbbOdfn06FtcJ9d0ShxxvSn2iUsGd/lgPIO2V3VZIPDbEaIj1/3nBBe1AwuEZKXVXkMmpr6LUAgMkLD/4D2PPA=="], - "wrangler/esbuild/@esbuild/openbsd-arm64": ["@esbuild/[email protected]", "", { "os": "openbsd", "cpu": "arm64" }, "sha512-Ct2WcFEANlFDtp1nVAXSNBPDxyU+j7+tId//iHXU2f/lN5AmO4zLyhDcpR5Cz1r08mVxzt3Jpyt4PmXQ1O6+7A=="], + "wrangler/esbuild/@esbuild/openbsd-arm64": ["@esbuild/[email protected]", "", { "os": "openbsd", "cpu": "arm64" }, "sha512-fWgqR8uNbCQ/GGv0yhzttj6sU/9Z5/Sv/VGU3F5OuXK6J6SlriONKrQ7tNlwBrJZXRYk5jUhuWvF7GYzGguBZQ=="], - "wrangler/esbuild/@esbuild/openbsd-x64": ["@esbuild/[email protected]", "", { "os": "openbsd", "cpu": "x64" }, "sha512-xAGGhyOQ9Otm1Xu8NT1ifGLnA6M3sJxZ6ixylb+vIUVzvvd6GOALpwQrYrtlPouMqd/vSbgehz6HaVk4+7Afhw=="], + "wrangler/esbuild/@esbuild/openbsd-x64": ["@esbuild/[email protected]", "", { "os": "openbsd", "cpu": "x64" }, "sha512-aCwlRdSNMNxkGGqQajMUza6uXzR/U0dIl1QmLjPtRbLOx3Gy3otfFu/VjATy4yQzo9yFDGTxYDo1FfAD9oRD2A=="], - "wrangler/esbuild/@esbuild/sunos-x64": ["@esbuild/[email protected]", "", { "os": "sunos", "cpu": "x64" }, "sha512-Mw+tzy4pp6wZEK0+Lwr76pWLjrtjmJyUB23tHKqEDP74R3q95luY/bXqXZeYl4NYlvwOqoRKlInQialgCKy67Q=="], + "wrangler/esbuild/@esbuild/openharmony-arm64": ["@esbuild/[email protected]", "", { "os": "none", "cpu": "arm64" }, "sha512-nyvsBccxNAsNYz2jVFYwEGuRRomqZ149A39SHWk4hV0jWxKM0hjBPm3AmdxcbHiFLbBSwG6SbpIcUbXjgyECfA=="], - "wrangler/esbuild/@esbuild/win32-arm64": ["@esbuild/[email protected]", "", { "os": "win32", "cpu": "arm64" }, "sha512-AVUP428VQTSddguz9dO9ngb+E5aScyg7nOeJDrF1HPYu555gmza3bDGMPhmVXL8svDSoqPCsCPjb265yG/kLKQ=="], + "wrangler/esbuild/@esbuild/sunos-x64": ["@esbuild/[email protected]", "", { "os": "sunos", "cpu": "x64" }, "sha512-Q1KY1iJafM+UX6CFEL+F4HRTgygmEW568YMqDA5UV97AuZSm21b7SXIrRJDwXWPzr8MGr75fUZPV67FdtMHlHA=="], - "wrangler/esbuild/@esbuild/win32-ia32": ["@esbuild/[email protected]", "", { "os": "win32", "cpu": "ia32" }, "sha512-i1sW+1i+oWvQzSgfRcxxG2k4I9n3O9NRqy8U+uugaT2Dy7kLO9Y7wI72haOahxceMX8hZAzgGou1FhndRldxRg=="], + "wrangler/esbuild/@esbuild/win32-arm64": ["@esbuild/[email protected]", "", { "os": "win32", "cpu": "arm64" }, "sha512-W1eyGNi6d+8kOmZIwi/EDjrL9nxQIQ0MiGqe/AWc6+IaHloxHSGoeRgDRKHFISThLmsewZ5nHFvGFWdBYlgKPg=="], - "wrangler/esbuild/@esbuild/win32-x64": ["@esbuild/[email protected]", "", { "os": "win32", "cpu": "x64" }, "sha512-nOT2vZNw6hJ+z43oP1SPea/G/6AbN6X+bGNhNuq8NtRHy4wsMhw765IKLNmnjek7GvjWBYQ8Q5VBoYTFg9y1UQ=="], + "wrangler/esbuild/@esbuild/win32-ia32": ["@esbuild/[email protected]", "", { "os": "win32", "cpu": "ia32" }, "sha512-30z1aKL9h22kQhilnYkORFYt+3wp7yZsHWus+wSKAJR8JtdfI76LJ4SBdMsCopTR3z/ORqVu5L1vtnHZWVj4cQ=="], + + "wrangler/esbuild/@esbuild/win32-x64": ["@esbuild/[email protected]", "", { "os": "win32", "cpu": "x64" }, "sha512-aIitBcjQeyOhMTImhLZmtxfdOcuNRpwlPNmlFKPcHQYPhEssw75Cl1TSXJXpMkzaua9FUetx/4OQKq7eJul5Cg=="], "wrap-ansi-cjs/string-width/emoji-regex": ["[email protected]", "", {}, "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A=="], @@ -6132,136 +6096,6 @@ "@puppeteer/browsers/yargs/string-width/strip-ansi": ["[email protected]", "", { "dependencies": { "ansi-regex": "^5.0.1" } }, "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A=="], - "@repo/web/wrangler/esbuild/@esbuild/aix-ppc64": ["@esbuild/[email protected]", "", { "os": "aix", "cpu": "ppc64" }, "sha512-KuZrd2hRjz01y5JK9mEBSD3Vj3mbCvemhT466rSuJYeE/hjuBrHfjjcjMdTm/sz7au+++sdbJZJmuBwQLuw68A=="], - - "@repo/web/wrangler/esbuild/@esbuild/android-arm": ["@esbuild/[email protected]", "", { "os": "android", "cpu": "arm" }, "sha512-j67aezrPNYWJEOHUNLPj9maeJte7uSMM6gMoxfPC9hOg8N02JuQi/T7ewumf4tNvJadFkvLZMlAq73b9uwdMyQ=="], - - "@repo/web/wrangler/esbuild/@esbuild/android-arm64": ["@esbuild/[email protected]", "", { "os": "android", "cpu": "arm64" }, "sha512-CC3vt4+1xZrs97/PKDkl0yN7w8edvU2vZvAFGD16n9F0Cvniy5qvzRXjfO1l94efczkkQE6g1x0i73Qf5uthOQ=="], - - "@repo/web/wrangler/esbuild/@esbuild/android-x64": ["@esbuild/[email protected]", "", { "os": "android", "cpu": "x64" }, "sha512-wurMkF1nmQajBO1+0CJmcN17U4BP6GqNSROP8t0X/Jiw2ltYGLHpEksp9MpoBqkrFR3kv2/te6Sha26k3+yZ9Q=="], - - "@repo/web/wrangler/esbuild/@esbuild/darwin-arm64": ["@esbuild/[email protected]", "", { "os": "darwin", "cpu": "arm64" }, "sha512-uJOQKYCcHhg07DL7i8MzjvS2LaP7W7Pn/7uA0B5S1EnqAirJtbyw4yC5jQ5qcFjHK9l6o/MX9QisBg12kNkdHg=="], - - "@repo/web/wrangler/esbuild/@esbuild/darwin-x64": ["@esbuild/[email protected]", "", { "os": "darwin", "cpu": "x64" }, "sha512-8mG6arH3yB/4ZXiEnXof5MK72dE6zM9cDvUcPtxhUZsDjESl9JipZYW60C3JGreKCEP+p8P/72r69m4AZGJd5g=="], - - "@repo/web/wrangler/esbuild/@esbuild/freebsd-arm64": ["@esbuild/[email protected]", "", { "os": "freebsd", "cpu": "arm64" }, "sha512-9FHtyO988CwNMMOE3YIeci+UV+x5Zy8fI2qHNpsEtSF83YPBmE8UWmfYAQg6Ux7Gsmd4FejZqnEUZCMGaNQHQw=="], - - "@repo/web/wrangler/esbuild/@esbuild/freebsd-x64": ["@esbuild/[email protected]", "", { "os": "freebsd", "cpu": "x64" }, "sha512-zCMeMXI4HS/tXvJz8vWGexpZj2YVtRAihHLk1imZj4efx1BQzN76YFeKqlDr3bUWI26wHwLWPd3rwh6pe4EV7g=="], - - "@repo/web/wrangler/esbuild/@esbuild/linux-arm": ["@esbuild/[email protected]", "", { "os": "linux", "cpu": "arm" }, "sha512-t76XLQDpxgmq2cNXKTVEB7O7YMb42atj2Re2Haf45HkaUpjM2J0UuJZDuaGbPbamzZ7bawyGFUkodL+zcE+jvQ=="], - - "@repo/web/wrangler/esbuild/@esbuild/linux-arm64": ["@esbuild/[email protected]", "", { "os": "linux", "cpu": "arm64" }, "sha512-AS18v0V+vZiLJyi/4LphvBE+OIX682Pu7ZYNsdUHyUKSoRwdnOsMf6FDekwoAFKej14WAkOef3zAORJgAtXnlQ=="], - - "@repo/web/wrangler/esbuild/@esbuild/linux-ia32": ["@esbuild/[email protected]", "", { "os": "linux", "cpu": "ia32" }, "sha512-Mz1jxqm/kfgKkc/KLHC5qIujMvnnarD9ra1cEcrs7qshTUSksPihGrWHVG5+osAIQ68577Zpww7SGapmzSt4Nw=="], - - "@repo/web/wrangler/esbuild/@esbuild/linux-loong64": ["@esbuild/[email protected]", "", { "os": "linux", "cpu": "none" }, "sha512-QbEREjdJeIreIAbdG2hLU1yXm1uu+LTdzoq1KCo4G4pFOLlvIspBm36QrQOar9LFduavoWX2msNFAAAY9j4BDg=="], - - "@repo/web/wrangler/esbuild/@esbuild/linux-mips64el": ["@esbuild/[email protected]", "", { "os": "linux", "cpu": "none" }, "sha512-sJz3zRNe4tO2wxvDpH/HYJilb6+2YJxo/ZNbVdtFiKDufzWq4JmKAiHy9iGoLjAV7r/W32VgaHGkk35cUXlNOg=="], - - "@repo/web/wrangler/esbuild/@esbuild/linux-ppc64": ["@esbuild/[email protected]", "", { "os": "linux", "cpu": "ppc64" }, "sha512-z9N10FBD0DCS2dmSABDBb5TLAyF1/ydVb+N4pi88T45efQ/w4ohr/F/QYCkxDPnkhkp6AIpIcQKQ8F0ANoA2JA=="], - - "@repo/web/wrangler/esbuild/@esbuild/linux-riscv64": ["@esbuild/[email protected]", "", { "os": "linux", "cpu": "none" }, "sha512-pQdyAIZ0BWIC5GyvVFn5awDiO14TkT/19FTmFcPdDec94KJ1uZcmFs21Fo8auMXzD4Tt+diXu1LW1gHus9fhFQ=="], - - "@repo/web/wrangler/esbuild/@esbuild/linux-s390x": ["@esbuild/[email protected]", "", { "os": "linux", "cpu": "s390x" }, "sha512-hPlRWR4eIDDEci953RI1BLZitgi5uqcsjKMxwYfmi4LcwyWo2IcRP+lThVnKjNtk90pLS8nKdroXYOqW+QQH+w=="], - - "@repo/web/wrangler/esbuild/@esbuild/linux-x64": ["@esbuild/[email protected]", "", { "os": "linux", "cpu": "x64" }, "sha512-1hBWx4OUJE2cab++aVZ7pObD6s+DK4mPGpemtnAORBvb5l/g5xFGk0vc0PjSkrDs0XaXj9yyob3d14XqvnQ4gw=="], - - "@repo/web/wrangler/esbuild/@esbuild/netbsd-arm64": ["@esbuild/[email protected]", "", { "os": "none", "cpu": "arm64" }, "sha512-6m0sfQfxfQfy1qRuecMkJlf1cIzTOgyaeXaiVaaki8/v+WB+U4hc6ik15ZW6TAllRlg/WuQXxWj1jx6C+dfy3w=="], - - "@repo/web/wrangler/esbuild/@esbuild/netbsd-x64": ["@esbuild/[email protected]", "", { "os": "none", "cpu": "x64" }, "sha512-xbbOdfn06FtcJ9d0ShxxvSn2iUsGd/lgPIO2V3VZIPDbEaIj1/3nBBe1AwuEZKXVXkMmpr6LUAgMkLD/4D2PPA=="], - - "@repo/web/wrangler/esbuild/@esbuild/openbsd-arm64": ["@esbuild/[email protected]", "", { "os": "openbsd", "cpu": "arm64" }, "sha512-fWgqR8uNbCQ/GGv0yhzttj6sU/9Z5/Sv/VGU3F5OuXK6J6SlriONKrQ7tNlwBrJZXRYk5jUhuWvF7GYzGguBZQ=="], - - "@repo/web/wrangler/esbuild/@esbuild/openbsd-x64": ["@esbuild/[email protected]", "", { "os": "openbsd", "cpu": "x64" }, "sha512-aCwlRdSNMNxkGGqQajMUza6uXzR/U0dIl1QmLjPtRbLOx3Gy3otfFu/VjATy4yQzo9yFDGTxYDo1FfAD9oRD2A=="], - - "@repo/web/wrangler/esbuild/@esbuild/openharmony-arm64": ["@esbuild/[email protected]", "", { "os": "none", "cpu": "arm64" }, "sha512-nyvsBccxNAsNYz2jVFYwEGuRRomqZ149A39SHWk4hV0jWxKM0hjBPm3AmdxcbHiFLbBSwG6SbpIcUbXjgyECfA=="], - - "@repo/web/wrangler/esbuild/@esbuild/sunos-x64": ["@esbuild/[email protected]", "", { "os": "sunos", "cpu": "x64" }, "sha512-Q1KY1iJafM+UX6CFEL+F4HRTgygmEW568YMqDA5UV97AuZSm21b7SXIrRJDwXWPzr8MGr75fUZPV67FdtMHlHA=="], - - "@repo/web/wrangler/esbuild/@esbuild/win32-arm64": ["@esbuild/[email protected]", "", { "os": "win32", "cpu": "arm64" }, "sha512-W1eyGNi6d+8kOmZIwi/EDjrL9nxQIQ0MiGqe/AWc6+IaHloxHSGoeRgDRKHFISThLmsewZ5nHFvGFWdBYlgKPg=="], - - "@repo/web/wrangler/esbuild/@esbuild/win32-ia32": ["@esbuild/[email protected]", "", { "os": "win32", "cpu": "ia32" }, "sha512-30z1aKL9h22kQhilnYkORFYt+3wp7yZsHWus+wSKAJR8JtdfI76LJ4SBdMsCopTR3z/ORqVu5L1vtnHZWVj4cQ=="], - - "@repo/web/wrangler/esbuild/@esbuild/win32-x64": ["@esbuild/[email protected]", "", { "os": "win32", "cpu": "x64" }, "sha512-aIitBcjQeyOhMTImhLZmtxfdOcuNRpwlPNmlFKPcHQYPhEssw75Cl1TSXJXpMkzaua9FUetx/4OQKq7eJul5Cg=="], - - "@repo/web/wrangler/miniflare/sharp": ["[email protected]", "", { "dependencies": { "color": "^4.2.3", "detect-libc": "^2.0.3", "semver": "^7.6.3" }, "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" } }, "sha512-haPVm1EkS9pgvHrQ/F3Xy+hgcuMV0Wm9vfIBSiwZ05k+xgb0PkBQpGsAA/oWdDobNaZTH5ppvHtzCFbnSEwHVw=="], - - "@repo/web/wrangler/miniflare/undici": ["[email protected]", "", {}, "sha512-Vqs8HTzjpQXZeXdpsfChQTlafcMQaaIwnGwLam1wudSSjlJeQ3bw1j+TLPePgrCnCpUXx7Ba5Pdpf5OBih62NQ=="], - - "@repo/web/wrangler/miniflare/ws": ["[email protected]", "", { "peerDependencies": { "bufferutil": "^4.0.1", "utf-8-validate": ">=5.0.2" }, "optionalPeers": ["bufferutil", "utf-8-validate"] }, "sha512-8VbfWfHLbbwu3+N6OKsOMpBdT4kXPDDB9cJk2bJ6mh9ucxdlnNvH1e+roYkKmN9Nxw2yjz7VzeO9oOz2zJ04Pw=="], - - "@repo/web/wrangler/miniflare/youch": ["[email protected]", "", { "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" } }, "sha512-rLfVLB4FgQneDr0dv1oddCVZmKjcJ6yX6mS4pU82Mq/Dt9a3cLZQ62pDBL4AUO+uVrCvtWz3ZFUL2HFAFJ/BXQ=="], - - "@repo/web/wrangler/miniflare/zod": ["[email protected]", "", {}, "sha512-EjIevzuJRiRPbVH4mGc8nApb/lVLKVpmUhAaR5R5doKGfAnGJ6Gr3CViAVjP+4FWSxCsybeWQdcgCtbX+7oZug=="], - - "@repo/web/wrangler/workerd/@cloudflare/workerd-darwin-64": ["@cloudflare/[email protected]", "", { "os": "darwin", "cpu": "x64" }, "sha512-/uvEAWEukTWb1geHhbjGUeZqcSSSyYzp0mvoPUBl+l0ont4NVGao3fgwM0q8wtKvgoKCHSG6zcG23wj9Opj3Nw=="], - - "@repo/web/wrangler/workerd/@cloudflare/workerd-darwin-arm64": ["@cloudflare/[email protected]", "", { "os": "darwin", "cpu": "arm64" }, "sha512-f52xRvcI9cWRd6400EZStRtXiRC5XKEud7K5aFIbbUv0VeINltujFQQ9nHWtsF6g1quIXWkjhh5u01gPAYNNXA=="], - - "@repo/web/wrangler/workerd/@cloudflare/workerd-linux-64": ["@cloudflare/[email protected]", "", { "os": "linux", "cpu": "x64" }, "sha512-HYXinF5RBH7oXbsFUMmwKCj+WltpYbf5mRKUBG5v3EuPhUjSIFB84U+58pDyfBJjcynHdy3EtvTWcvh/+lcgow=="], - - "@repo/web/wrangler/workerd/@cloudflare/workerd-linux-arm64": ["@cloudflare/[email protected]", "", { "os": "linux", "cpu": "arm64" }, "sha512-++L02Jdoxz7hEA9qDaQjbVU1RzQS+S+eqIi22DkPe2Tgiq2M3UfNpeu+75k5L9DGRIkZPYvwMBMbcmKvQqdIIg=="], - - "@repo/web/wrangler/workerd/@cloudflare/workerd-windows-64": ["@cloudflare/[email protected]", "", { "os": "win32", "cpu": "x64" }, "sha512-gzeU6eDydTi7ib+Q9DD/c0hpXtqPucnHk2tfGU03mljPObYxzMkkPGgB5qxpksFvub3y4K0ChjqYxGJB4F+j3g=="], - - "alchemy/@cloudflare/unenv-preset/workerd/@cloudflare/workerd-darwin-64": ["@cloudflare/[email protected]", "", { "os": "darwin", "cpu": "x64" }, "sha512-/uvEAWEukTWb1geHhbjGUeZqcSSSyYzp0mvoPUBl+l0ont4NVGao3fgwM0q8wtKvgoKCHSG6zcG23wj9Opj3Nw=="], - - "alchemy/@cloudflare/unenv-preset/workerd/@cloudflare/workerd-darwin-arm64": ["@cloudflare/[email protected]", "", { "os": "darwin", "cpu": "arm64" }, "sha512-f52xRvcI9cWRd6400EZStRtXiRC5XKEud7K5aFIbbUv0VeINltujFQQ9nHWtsF6g1quIXWkjhh5u01gPAYNNXA=="], - - "alchemy/@cloudflare/unenv-preset/workerd/@cloudflare/workerd-linux-64": ["@cloudflare/[email protected]", "", { "os": "linux", "cpu": "x64" }, "sha512-HYXinF5RBH7oXbsFUMmwKCj+WltpYbf5mRKUBG5v3EuPhUjSIFB84U+58pDyfBJjcynHdy3EtvTWcvh/+lcgow=="], - - "alchemy/@cloudflare/unenv-preset/workerd/@cloudflare/workerd-linux-arm64": ["@cloudflare/[email protected]", "", { "os": "linux", "cpu": "arm64" }, "sha512-++L02Jdoxz7hEA9qDaQjbVU1RzQS+S+eqIi22DkPe2Tgiq2M3UfNpeu+75k5L9DGRIkZPYvwMBMbcmKvQqdIIg=="], - - "alchemy/@cloudflare/unenv-preset/workerd/@cloudflare/workerd-windows-64": ["@cloudflare/[email protected]", "", { "os": "win32", "cpu": "x64" }, "sha512-gzeU6eDydTi7ib+Q9DD/c0hpXtqPucnHk2tfGU03mljPObYxzMkkPGgB5qxpksFvub3y4K0ChjqYxGJB4F+j3g=="], - - "alchemy/miniflare/sharp/@img/sharp-darwin-arm64": ["@img/[email protected]", "", { "optionalDependencies": { "@img/sharp-libvips-darwin-arm64": "1.0.4" }, "os": "darwin", "cpu": "arm64" }, "sha512-UT4p+iz/2H4twwAoLCqfA9UH5pI6DggwKEGuaPy7nCVQ8ZsiY5PIcrRvD1DzuY3qYL07NtIQcWnBSY/heikIFQ=="], - - "alchemy/miniflare/sharp/@img/sharp-darwin-x64": ["@img/[email protected]", "", { "optionalDependencies": { "@img/sharp-libvips-darwin-x64": "1.0.4" }, "os": "darwin", "cpu": "x64" }, "sha512-fyHac4jIc1ANYGRDxtiqelIbdWkIuQaI84Mv45KvGRRxSAa7o7d1ZKAOBaYbnepLC1WqxfpimdeWfvqqSGwR2Q=="], - - "alchemy/miniflare/sharp/@img/sharp-libvips-darwin-arm64": ["@img/[email protected]", "", { "os": "darwin", "cpu": "arm64" }, "sha512-XblONe153h0O2zuFfTAbQYAX2JhYmDHeWikp1LM9Hul9gVPjFY427k6dFEcOL72O01QxQsWi761svJ/ev9xEDg=="], - - "alchemy/miniflare/sharp/@img/sharp-libvips-darwin-x64": ["@img/[email protected]", "", { "os": "darwin", "cpu": "x64" }, "sha512-xnGR8YuZYfJGmWPvmlunFaWJsb9T/AO2ykoP3Fz/0X5XV2aoYBPkX6xqCQvUTKKiLddarLaxpzNe+b1hjeWHAQ=="], - - "alchemy/miniflare/sharp/@img/sharp-libvips-linux-arm": ["@img/[email protected]", "", { "os": "linux", "cpu": "arm" }, "sha512-gvcC4ACAOPRNATg/ov8/MnbxFDJqf/pDePbBnuBDcjsI8PssmjoKMAz4LtLaVi+OnSb5FK/yIOamqDwGmXW32g=="], - - "alchemy/miniflare/sharp/@img/sharp-libvips-linux-arm64": ["@img/[email protected]", "", { "os": "linux", "cpu": "arm64" }, "sha512-9B+taZ8DlyyqzZQnoeIvDVR/2F4EbMepXMc/NdVbkzsJbzkUjhXv/70GQJ7tdLA4YJgNP25zukcxpX2/SueNrA=="], - - "alchemy/miniflare/sharp/@img/sharp-libvips-linux-s390x": ["@img/[email protected]", "", { "os": "linux", "cpu": "s390x" }, "sha512-u7Wz6ntiSSgGSGcjZ55im6uvTrOxSIS8/dgoVMoiGE9I6JAfU50yH5BoDlYA1tcuGS7g/QNtetJnxA6QEsCVTA=="], - - "alchemy/miniflare/sharp/@img/sharp-libvips-linux-x64": ["@img/[email protected]", "", { "os": "linux", "cpu": "x64" }, "sha512-MmWmQ3iPFZr0Iev+BAgVMb3ZyC4KeFc3jFxnNbEPas60e1cIfevbtuyf9nDGIzOaW9PdnDciJm+wFFaTlj5xYw=="], - - "alchemy/miniflare/sharp/@img/sharp-libvips-linuxmusl-arm64": ["@img/[email protected]", "", { "os": "linux", "cpu": "arm64" }, "sha512-9Ti+BbTYDcsbp4wfYib8Ctm1ilkugkA/uscUn6UXK1ldpC1JjiXbLfFZtRlBhjPZ5o1NCLiDbg8fhUPKStHoTA=="], - - "alchemy/miniflare/sharp/@img/sharp-libvips-linuxmusl-x64": ["@img/[email protected]", "", { "os": "linux", "cpu": "x64" }, "sha512-viYN1KX9m+/hGkJtvYYp+CCLgnJXwiQB39damAO7WMdKWlIhmYTfHjwSbQeUK/20vY154mwezd9HflVFM1wVSw=="], - - "alchemy/miniflare/sharp/@img/sharp-linux-arm": ["@img/[email protected]", "", { "optionalDependencies": { "@img/sharp-libvips-linux-arm": "1.0.5" }, "os": "linux", "cpu": "arm" }, "sha512-JTS1eldqZbJxjvKaAkxhZmBqPRGmxgu+qFKSInv8moZ2AmT5Yib3EQ1c6gp493HvrvV8QgdOXdyaIBrhvFhBMQ=="], - - "alchemy/miniflare/sharp/@img/sharp-linux-arm64": ["@img/[email protected]", "", { "optionalDependencies": { "@img/sharp-libvips-linux-arm64": "1.0.4" }, "os": "linux", "cpu": "arm64" }, "sha512-JMVv+AMRyGOHtO1RFBiJy/MBsgz0x4AWrT6QoEVVTyh1E39TrCUpTRI7mx9VksGX4awWASxqCYLCV4wBZHAYxA=="], - - "alchemy/miniflare/sharp/@img/sharp-linux-s390x": ["@img/[email protected]", "", { "optionalDependencies": { "@img/sharp-libvips-linux-s390x": "1.0.4" }, "os": "linux", "cpu": "s390x" }, "sha512-y/5PCd+mP4CA/sPDKl2961b+C9d+vPAveS33s6Z3zfASk2j5upL6fXVPZi7ztePZ5CuH+1kW8JtvxgbuXHRa4Q=="], - - "alchemy/miniflare/sharp/@img/sharp-linux-x64": ["@img/[email protected]", "", { "optionalDependencies": { "@img/sharp-libvips-linux-x64": "1.0.4" }, "os": "linux", "cpu": "x64" }, "sha512-opC+Ok5pRNAzuvq1AG0ar+1owsu842/Ab+4qvU879ippJBHvyY5n2mxF1izXqkPYlGuP/M556uh53jRLJmzTWA=="], - - "alchemy/miniflare/sharp/@img/sharp-linuxmusl-arm64": ["@img/[email protected]", "", { "optionalDependencies": { "@img/sharp-libvips-linuxmusl-arm64": "1.0.4" }, "os": "linux", "cpu": "arm64" }, "sha512-XrHMZwGQGvJg2V/oRSUfSAfjfPxO+4DkiRh6p2AFjLQztWUuY/o8Mq0eMQVIY7HJ1CDQUJlxGGZRw1a5bqmd1g=="], - - "alchemy/miniflare/sharp/@img/sharp-linuxmusl-x64": ["@img/[email protected]", "", { "optionalDependencies": { "@img/sharp-libvips-linuxmusl-x64": "1.0.4" }, "os": "linux", "cpu": "x64" }, "sha512-WT+d/cgqKkkKySYmqoZ8y3pxx7lx9vVejxW/W4DOFMYVSkErR+w7mf2u8m/y4+xHe7yY9DAXQMWQhpnMuFfScw=="], - - "alchemy/miniflare/sharp/@img/sharp-wasm32": ["@img/[email protected]", "", { "dependencies": { "@emnapi/runtime": "^1.2.0" }, "cpu": "none" }, "sha512-ykUW4LVGaMcU9lu9thv85CbRMAwfeadCJHRsg2GmeRa/cJxsVY9Rbd57JcMxBkKHag5U/x7TSBpScF4U8ElVzg=="], - - "alchemy/miniflare/sharp/@img/sharp-win32-ia32": ["@img/[email protected]", "", { "os": "win32", "cpu": "ia32" }, "sha512-T36PblLaTwuVJ/zw/LaH0PdZkRz5rd3SmMHX8GSmR7vtNSP5Z6bQkExdSK7xGWyxLw4sUknBuugTelgw2faBbQ=="], - - "alchemy/miniflare/sharp/@img/sharp-win32-x64": ["@img/[email protected]", "", { "os": "win32", "cpu": "x64" }, "sha512-MpY/o8/8kj+EcnxwvrP4aTJSWw/aZ7JIGR4aBeZkZw5B7/Jn+tY9/VNwtcoGmdT7GfggGIU4kygOMSbYnOrAbg=="], - - "alchemy/miniflare/workerd/@cloudflare/workerd-darwin-64": ["@cloudflare/[email protected]", "", { "os": "darwin", "cpu": "x64" }, "sha512-/uvEAWEukTWb1geHhbjGUeZqcSSSyYzp0mvoPUBl+l0ont4NVGao3fgwM0q8wtKvgoKCHSG6zcG23wj9Opj3Nw=="], - - "alchemy/miniflare/workerd/@cloudflare/workerd-darwin-arm64": ["@cloudflare/[email protected]", "", { "os": "darwin", "cpu": "arm64" }, "sha512-f52xRvcI9cWRd6400EZStRtXiRC5XKEud7K5aFIbbUv0VeINltujFQQ9nHWtsF6g1quIXWkjhh5u01gPAYNNXA=="], - - "alchemy/miniflare/workerd/@cloudflare/workerd-linux-64": ["@cloudflare/[email protected]", "", { "os": "linux", "cpu": "x64" }, "sha512-HYXinF5RBH7oXbsFUMmwKCj+WltpYbf5mRKUBG5v3EuPhUjSIFB84U+58pDyfBJjcynHdy3EtvTWcvh/+lcgow=="], - - "alchemy/miniflare/workerd/@cloudflare/workerd-linux-arm64": ["@cloudflare/[email protected]", "", { "os": "linux", "cpu": "arm64" }, "sha512-++L02Jdoxz7hEA9qDaQjbVU1RzQS+S+eqIi22DkPe2Tgiq2M3UfNpeu+75k5L9DGRIkZPYvwMBMbcmKvQqdIIg=="], - - "alchemy/miniflare/workerd/@cloudflare/workerd-windows-64": ["@cloudflare/[email protected]", "", { "os": "win32", "cpu": "x64" }, "sha512-gzeU6eDydTi7ib+Q9DD/c0hpXtqPucnHk2tfGU03mljPObYxzMkkPGgB5qxpksFvub3y4K0ChjqYxGJB4F+j3g=="], - "ansi-align/string-width/strip-ansi/ansi-regex": ["[email protected]", "", {}, "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ=="], "memory-graph-playground/next/postcss/nanoid": ["[email protected]", "", { "bin": { "nanoid": "bin/nanoid.cjs" } }, "sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w=="], @@ -6303,43 +6137,5 @@ "@puppeteer/browsers/yargs/cliui/wrap-ansi/ansi-styles": ["[email protected]", "", { "dependencies": { "color-convert": "^2.0.1" } }, "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg=="], "@puppeteer/browsers/yargs/string-width/strip-ansi/ansi-regex": ["[email protected]", "", {}, "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ=="], - - "@repo/web/wrangler/miniflare/sharp/@img/sharp-darwin-arm64": ["@img/[email protected]", "", { "optionalDependencies": { "@img/sharp-libvips-darwin-arm64": "1.0.4" }, "os": "darwin", "cpu": "arm64" }, "sha512-UT4p+iz/2H4twwAoLCqfA9UH5pI6DggwKEGuaPy7nCVQ8ZsiY5PIcrRvD1DzuY3qYL07NtIQcWnBSY/heikIFQ=="], - - "@repo/web/wrangler/miniflare/sharp/@img/sharp-darwin-x64": ["@img/[email protected]", "", { "optionalDependencies": { "@img/sharp-libvips-darwin-x64": "1.0.4" }, "os": "darwin", "cpu": "x64" }, "sha512-fyHac4jIc1ANYGRDxtiqelIbdWkIuQaI84Mv45KvGRRxSAa7o7d1ZKAOBaYbnepLC1WqxfpimdeWfvqqSGwR2Q=="], - - "@repo/web/wrangler/miniflare/sharp/@img/sharp-libvips-darwin-arm64": ["@img/[email protected]", "", { "os": "darwin", "cpu": "arm64" }, "sha512-XblONe153h0O2zuFfTAbQYAX2JhYmDHeWikp1LM9Hul9gVPjFY427k6dFEcOL72O01QxQsWi761svJ/ev9xEDg=="], - - "@repo/web/wrangler/miniflare/sharp/@img/sharp-libvips-darwin-x64": ["@img/[email protected]", "", { "os": "darwin", "cpu": "x64" }, "sha512-xnGR8YuZYfJGmWPvmlunFaWJsb9T/AO2ykoP3Fz/0X5XV2aoYBPkX6xqCQvUTKKiLddarLaxpzNe+b1hjeWHAQ=="], - - "@repo/web/wrangler/miniflare/sharp/@img/sharp-libvips-linux-arm": ["@img/[email protected]", "", { "os": "linux", "cpu": "arm" }, "sha512-gvcC4ACAOPRNATg/ov8/MnbxFDJqf/pDePbBnuBDcjsI8PssmjoKMAz4LtLaVi+OnSb5FK/yIOamqDwGmXW32g=="], - - "@repo/web/wrangler/miniflare/sharp/@img/sharp-libvips-linux-arm64": ["@img/[email protected]", "", { "os": "linux", "cpu": "arm64" }, "sha512-9B+taZ8DlyyqzZQnoeIvDVR/2F4EbMepXMc/NdVbkzsJbzkUjhXv/70GQJ7tdLA4YJgNP25zukcxpX2/SueNrA=="], - - "@repo/web/wrangler/miniflare/sharp/@img/sharp-libvips-linux-s390x": ["@img/[email protected]", "", { "os": "linux", "cpu": "s390x" }, "sha512-u7Wz6ntiSSgGSGcjZ55im6uvTrOxSIS8/dgoVMoiGE9I6JAfU50yH5BoDlYA1tcuGS7g/QNtetJnxA6QEsCVTA=="], - - "@repo/web/wrangler/miniflare/sharp/@img/sharp-libvips-linux-x64": ["@img/[email protected]", "", { "os": "linux", "cpu": "x64" }, "sha512-MmWmQ3iPFZr0Iev+BAgVMb3ZyC4KeFc3jFxnNbEPas60e1cIfevbtuyf9nDGIzOaW9PdnDciJm+wFFaTlj5xYw=="], - - "@repo/web/wrangler/miniflare/sharp/@img/sharp-libvips-linuxmusl-arm64": ["@img/[email protected]", "", { "os": "linux", "cpu": "arm64" }, "sha512-9Ti+BbTYDcsbp4wfYib8Ctm1ilkugkA/uscUn6UXK1ldpC1JjiXbLfFZtRlBhjPZ5o1NCLiDbg8fhUPKStHoTA=="], - - "@repo/web/wrangler/miniflare/sharp/@img/sharp-libvips-linuxmusl-x64": ["@img/[email protected]", "", { "os": "linux", "cpu": "x64" }, "sha512-viYN1KX9m+/hGkJtvYYp+CCLgnJXwiQB39damAO7WMdKWlIhmYTfHjwSbQeUK/20vY154mwezd9HflVFM1wVSw=="], - - "@repo/web/wrangler/miniflare/sharp/@img/sharp-linux-arm": ["@img/[email protected]", "", { "optionalDependencies": { "@img/sharp-libvips-linux-arm": "1.0.5" }, "os": "linux", "cpu": "arm" }, "sha512-JTS1eldqZbJxjvKaAkxhZmBqPRGmxgu+qFKSInv8moZ2AmT5Yib3EQ1c6gp493HvrvV8QgdOXdyaIBrhvFhBMQ=="], - - "@repo/web/wrangler/miniflare/sharp/@img/sharp-linux-arm64": ["@img/[email protected]", "", { "optionalDependencies": { "@img/sharp-libvips-linux-arm64": "1.0.4" }, "os": "linux", "cpu": "arm64" }, "sha512-JMVv+AMRyGOHtO1RFBiJy/MBsgz0x4AWrT6QoEVVTyh1E39TrCUpTRI7mx9VksGX4awWASxqCYLCV4wBZHAYxA=="], - - "@repo/web/wrangler/miniflare/sharp/@img/sharp-linux-s390x": ["@img/[email protected]", "", { "optionalDependencies": { "@img/sharp-libvips-linux-s390x": "1.0.4" }, "os": "linux", "cpu": "s390x" }, "sha512-y/5PCd+mP4CA/sPDKl2961b+C9d+vPAveS33s6Z3zfASk2j5upL6fXVPZi7ztePZ5CuH+1kW8JtvxgbuXHRa4Q=="], - - "@repo/web/wrangler/miniflare/sharp/@img/sharp-linux-x64": ["@img/[email protected]", "", { "optionalDependencies": { "@img/sharp-libvips-linux-x64": "1.0.4" }, "os": "linux", "cpu": "x64" }, "sha512-opC+Ok5pRNAzuvq1AG0ar+1owsu842/Ab+4qvU879ippJBHvyY5n2mxF1izXqkPYlGuP/M556uh53jRLJmzTWA=="], - - "@repo/web/wrangler/miniflare/sharp/@img/sharp-linuxmusl-arm64": ["@img/[email protected]", "", { "optionalDependencies": { "@img/sharp-libvips-linuxmusl-arm64": "1.0.4" }, "os": "linux", "cpu": "arm64" }, "sha512-XrHMZwGQGvJg2V/oRSUfSAfjfPxO+4DkiRh6p2AFjLQztWUuY/o8Mq0eMQVIY7HJ1CDQUJlxGGZRw1a5bqmd1g=="], - - "@repo/web/wrangler/miniflare/sharp/@img/sharp-linuxmusl-x64": ["@img/[email protected]", "", { "optionalDependencies": { "@img/sharp-libvips-linuxmusl-x64": "1.0.4" }, "os": "linux", "cpu": "x64" }, "sha512-WT+d/cgqKkkKySYmqoZ8y3pxx7lx9vVejxW/W4DOFMYVSkErR+w7mf2u8m/y4+xHe7yY9DAXQMWQhpnMuFfScw=="], - - "@repo/web/wrangler/miniflare/sharp/@img/sharp-wasm32": ["@img/[email protected]", "", { "dependencies": { "@emnapi/runtime": "^1.2.0" }, "cpu": "none" }, "sha512-ykUW4LVGaMcU9lu9thv85CbRMAwfeadCJHRsg2GmeRa/cJxsVY9Rbd57JcMxBkKHag5U/x7TSBpScF4U8ElVzg=="], - - "@repo/web/wrangler/miniflare/sharp/@img/sharp-win32-ia32": ["@img/[email protected]", "", { "os": "win32", "cpu": "ia32" }, "sha512-T36PblLaTwuVJ/zw/LaH0PdZkRz5rd3SmMHX8GSmR7vtNSP5Z6bQkExdSK7xGWyxLw4sUknBuugTelgw2faBbQ=="], - - "@repo/web/wrangler/miniflare/sharp/@img/sharp-win32-x64": ["@img/[email protected]", "", { "os": "win32", "cpu": "x64" }, "sha512-MpY/o8/8kj+EcnxwvrP4aTJSWw/aZ7JIGR4aBeZkZw5B7/Jn+tY9/VNwtcoGmdT7GfggGIU4kygOMSbYnOrAbg=="], } } diff --git a/package.json b/package.json index 95d9d7e7..bc1ba62b 100644 --- a/package.json +++ b/package.json @@ -31,7 +31,7 @@ "@scalar/hono-api-reference": "^0.9.11", "@vanilla-extract/recipes": "^0.5.7", "ai": "^5.0.59", - "alchemy": "^0.55.2", + "alchemy": "^0.81.4", "atmn": "^0.0.16", "better-auth": "^1.3.3", "boxen": "^8.0.1", @@ -61,7 +61,7 @@ "drizzle-kit": "^0.31.4", "turbo": "^2.5.4", "typescript": "5.8.3", - "wrangler": "4.22.0" + "wrangler": "^4.42.2" }, "workerd": { "import": "./esm/index.mjs", diff --git a/packages/memory-graph/CHANGELOG.md b/packages/memory-graph/CHANGELOG.md new file mode 100644 index 00000000..004d6681 --- /dev/null +++ b/packages/memory-graph/CHANGELOG.md @@ -0,0 +1,103 @@ +# Memory Graph Changelog + +## Development Setup + +To test changes, run these commands in separate terminals: + +**Terminal 1** - Install the required dependencies: +```bash +bun install +``` + +**Terminal 1** - Build memory-graph in watch mode: +```bash +cd packages/memory-graph && bun run dev +``` + +**Terminal 2** - Run the playground: +```bash +cd apps/memory-graph-playground && bun run dev +``` + +Then open http://localhost:3000 in your browser. + +--- + +### Features + +#### Slideshow Mode +Auto-cycling through nodes with smooth animations and physics simulation +- Random node selection every 3.5s (avoids consecutive duplicates) +- Smooth pan-to-node animation with automatic popover +- Brief physics pulse (1s) on each selection +- Background dimming animation +- Single-click to stop + +#### Node Popover with Background Dimming +Floating popover with smart positioning and focus dimming effect +- Smooth 1.5s cubic ease-out dimming animation +- Non-selected nodes: 20% opacity, unconnected edges: 10% opacity +- Smart edge detection with 20px gap from node +- Auto-flips to avoid viewport edges +- Close via backdrop click, X button, or Escape key +- Shows: title, summary, type, memory count, URL, date, ID + +#### Document Type Icons +Canvas-rendered icons centered on document cards +- Supported: TXT, PDF, MD, DOC/DOCX, RTF, CSV, JSON +- Scales with card size (40% of height) +- Only renders when zoomed in + +#### Physics-Driven Layout +Simplified initial positioning, letting physics create natural layouts +- Simple grid with random offsets (no concentric rings) +- 50 quick pre-ticks + smooth animation +- Eliminates teleportation on node interaction +- Faster, non-blocking initial render + +#### Updated Color Scheme +Refined palette for better contrast and readability + +### Bug Fixes + +#### Edge Viewport Culling +Fixed edges disappearing during zoom/pan +- Now checks both X and Y axis bounds +- Only culls when BOTH endpoints off-screen in same direction +- 100px margin on all sides + +#### Memory Nodes Follow Parents +Memory nodes now move with parent documents when dragged +- Store relative offset instead of absolute position +- Automatically repositions based on parent location + +### Performance + +#### k-NN Similarity Algorithm +Reduced from O(n²) to O(n·k) +- 3x faster: ~50ms → ~17ms for 100 docs +- 4,950 → 1,500 comparisons for 100 docs +- Separated into own memo (doesn't recalculate on UI interactions) + +#### Memory Leak Fix +NodeCache now cleans up deleted nodes properly + +#### Race Condition Fix +Atomic node/edge updates eliminate NaN positions + +#### Canvas Rendering Optimizations +Reduced per-frame overhead and improved rendering efficiency +- Spatial grid for hit detection +- Batched edge rendering by type (fewer canvas state changes) +- Canvas quality settings initialized once instead of every frame +- Optimized render key using fast hash instead of string concatenation +- Memoized nodeMap to avoid rebuilding every frame + +#### Node Limiting & Memory Management +Smart memory limiting prevents performance issues with large datasets +- `maxNodes` prop limits total memory nodes (default: 500 in playground) +- Dynamic per-document cap distributes budget across documents +- Prioritizes recent memories and high-relevance scores +- k-NN similarity limit reduced from 15 to 10 connections per document + +---
\ No newline at end of file diff --git a/packages/memory-graph/package.json b/packages/memory-graph/package.json index e356619f..41967829 100644 --- a/packages/memory-graph/package.json +++ b/packages/memory-graph/package.json @@ -65,6 +65,7 @@ "@vanilla-extract/css": "^1.17.4", "@vanilla-extract/recipes": "^0.5.7", "@vanilla-extract/sprinkles": "^1.6.5", + "d3-force": "^3.0.0", "lucide-react": "^0.552.0", "motion": "^12.23.24" }, diff --git a/packages/memory-graph/src/components/graph-canvas.tsx b/packages/memory-graph/src/components/graph-canvas.tsx index ee4f5885..28dd53c7 100644 --- a/packages/memory-graph/src/components/graph-canvas.tsx +++ b/packages/memory-graph/src/components/graph-canvas.tsx @@ -7,14 +7,16 @@ import { useLayoutEffect, useMemo, useRef, + useState, } from "react" -import { colors } from "@/constants" +import { colors, ANIMATION } from "@/constants" import type { DocumentWithMemories, GraphCanvasProps, GraphNode, MemoryEntry, } from "@/types" +import { drawDocumentIcon } from "@/utils/document-icons" import { canvasWrapper } from "./canvas-common.css" export const GraphCanvas = memo<GraphCanvasProps>( @@ -41,39 +43,154 @@ export const GraphCanvas = memo<GraphCanvasProps>( onTouchEnd, draggingNodeId, highlightDocumentIds, + isSimulationActive = false, + selectedNodeId = null, }) => { const canvasRef = useRef<HTMLCanvasElement>(null) const animationRef = useRef<number>(0) const startTimeRef = useRef<number>(Date.now()) const mousePos = useRef<{ x: number; y: number }>({ x: 0, y: 0 }) const currentHoveredNode = useRef<string | null>(null) + const dimProgress = useRef<number>(selectedNodeId ? 1 : 0) + const dimAnimationRef = useRef<number>(0) + const [, forceRender] = useState(0) // Initialize start time once useEffect(() => { startTimeRef.current = Date.now() }, []) - // Efficient hit detection + // Initialize canvas quality settings once + useLayoutEffect(() => { + const canvas = canvasRef.current + if (!canvas) return + const ctx = canvas.getContext("2d") + if (!ctx) return + + // Set high quality rendering once instead of every frame + ctx.imageSmoothingEnabled = true + ctx.imageSmoothingQuality = "high" + }, []) + + // Smooth dimming animation + useEffect(() => { + const targetDim = selectedNodeId ? 1 : 0 + const duration = ANIMATION.dimDuration // Match physics settling time + const startDim = dimProgress.current + const startTime = Date.now() + + const animate = () => { + const elapsed = Date.now() - startTime + const progress = Math.min(elapsed / duration, 1) + + // Ease-out cubic easing for smooth deceleration + const eased = 1 - Math.pow(1 - progress, 3) + dimProgress.current = startDim + (targetDim - startDim) * eased + + // Force re-render to update canvas during animation + forceRender(prev => prev + 1) + + if (progress < 1) { + dimAnimationRef.current = requestAnimationFrame(animate) + } + } + + if (dimAnimationRef.current) { + cancelAnimationFrame(dimAnimationRef.current) + } + animate() + + return () => { + if (dimAnimationRef.current) { + cancelAnimationFrame(dimAnimationRef.current) + } + } + }, [selectedNodeId]) + + // Spatial grid for optimized hit detection (20-25% FPS improvement for large graphs) + const spatialGrid = useMemo(() => { + const GRID_CELL_SIZE = 150 // Grid cell size in screen pixels + const grid = new Map<string, GraphNode[]>() + + // Build spatial grid + nodes.forEach((node) => { + const screenX = node.x * zoom + panX + const screenY = node.y * zoom + panY + + // Calculate which grid cell this node belongs to + const cellX = Math.floor(screenX / GRID_CELL_SIZE) + const cellY = Math.floor(screenY / GRID_CELL_SIZE) + const cellKey = `${cellX},${cellY}` + + // Add node to grid cell + if (!grid.has(cellKey)) { + grid.set(cellKey, []) + } + grid.get(cellKey)!.push(node) + }) + + return { grid, cellSize: GRID_CELL_SIZE } + }, [nodes, panX, panY, zoom]) + + // Efficient hit detection using spatial grid const getNodeAtPosition = useCallback( (x: number, y: number): string | null => { + const { grid, cellSize } = spatialGrid + + // Determine which grid cell the click is in + const cellX = Math.floor(x / cellSize) + const cellY = Math.floor(y / cellSize) + const cellKey = `${cellX},${cellY}` + + // Only check nodes in the clicked cell (and neighboring cells for edge cases) + const cellsToCheck = [ + cellKey, + `${cellX-1},${cellY}`, `${cellX+1},${cellY}`, + `${cellX},${cellY-1}`, `${cellX},${cellY+1}`, + ] + // Check from top-most to bottom-most: memory nodes are drawn after documents - for (let i = nodes.length - 1; i >= 0; i--) { - const node = nodes[i]! - const screenX = node.x * zoom + panX - const screenY = node.y * zoom + panY - const nodeSize = node.size * zoom - - const dx = x - screenX - const dy = y - screenY - const distance = Math.sqrt(dx * dx + dy * dy) + for (const key of cellsToCheck) { + const cellNodes = grid.get(key) + if (!cellNodes) continue + + // Iterate backwards (top-most first) + for (let i = cellNodes.length - 1; i >= 0; i--) { + const node = cellNodes[i]! + const screenX = node.x * zoom + panX + const screenY = node.y * zoom + panY + const nodeSize = node.size * zoom + + if (node.type === "document") { + // Rectangular hit detection for documents (matches visual size) + const docWidth = nodeSize * 1.4 + const docHeight = nodeSize * 0.9 + const halfW = docWidth / 2 + const halfH = docHeight / 2 + + if ( + x >= screenX - halfW && + x <= screenX + halfW && + y >= screenY - halfH && + y <= screenY + halfH + ) { + return node.id + } + } else { + // Circular hit detection for memory nodes + const dx = x - screenX + const dy = y - screenY + const distance = Math.sqrt(dx * dx + dy * dy) - if (distance <= nodeSize / 2) { - return node.id + if (distance <= nodeSize / 2) { + return node.id + } + } } } return null }, - [nodes, panX, panY, zoom], + [spatialGrid, panX, panY, zoom], ) // Handle mouse events @@ -140,6 +257,11 @@ export const GraphCanvas = memo<GraphCanvasProps>( [getNodeAtPosition, onNodeClick], ) + // Memoize nodeMap to avoid rebuilding every frame + const nodeMap = useMemo(() => { + return new Map(nodes.map((node) => [node.id, node])) + }, [nodes]) + // Professional rendering function with LOD const render = useCallback(() => { const canvas = canvasRef.current @@ -157,10 +279,6 @@ export const GraphCanvas = memo<GraphCanvasProps>( // Clear canvas ctx.clearRect(0, 0, width, height) - // Set high quality rendering - ctx.imageSmoothingEnabled = true - ctx.imageSmoothingQuality = "high" - // Draw minimal background grid ctx.strokeStyle = "rgba(148, 163, 184, 0.03)" // Very subtle grid ctx.lineWidth = 1 @@ -182,14 +300,25 @@ export const GraphCanvas = memo<GraphCanvasProps>( ctx.stroke() } - // Create node lookup map - const nodeMap = new Map(nodes.map((node) => [node.id, node])) - - // Draw enhanced edges with sophisticated styling + // Draw enhanced edges with sophisticated styling - BATCHED BY TYPE for performance ctx.lineCap = "round" + + // Group edges by type for batch rendering (reduces canvas state changes) + const docMemoryEdges: typeof edges = [] + const docDocEdges: typeof edges = [] + const versionEdges: typeof edges = [] + + // Categorize edges (single pass) with viewport culling edges.forEach((edge) => { - const sourceNode = nodeMap.get(edge.source) - const targetNode = nodeMap.get(edge.target) + // Handle both string IDs and node references (d3-force mutates these) + const sourceNode = + typeof edge.source === "string" + ? nodeMap.get(edge.source) + : edge.source + const targetNode = + typeof edge.target === "string" + ? nodeMap.get(edge.target) + : edge.target if (sourceNode && targetNode) { const sourceX = sourceNode.x * zoom + panX @@ -197,12 +326,14 @@ export const GraphCanvas = memo<GraphCanvasProps>( const targetX = targetNode.x * zoom + panX const targetY = targetNode.y * zoom + panY - // Enhanced viewport culling with edge type considerations + // Enhanced viewport culling with proper X and Y axis bounds checking + // Only cull edges when BOTH endpoints are off-screen in the same direction + const edgeMargin = 100 if ( - sourceX < -100 || - sourceX > width + 100 || - targetX < -100 || - targetX > width + 100 + (sourceX < -edgeMargin && targetX < -edgeMargin) || + (sourceX > width + edgeMargin && targetX > width + edgeMargin) || + (sourceY < -edgeMargin && targetY < -edgeMargin) || + (sourceY > height + edgeMargin && targetY > height + edgeMargin) ) { return } @@ -217,43 +348,152 @@ export const GraphCanvas = memo<GraphCanvasProps>( } } - // Enhanced connection styling based on edge type - let connectionColor = colors.connection.weak - let dashPattern: number[] = [] - let opacity = edge.visualProps.opacity - let lineWidth = Math.max(1, edge.visualProps.thickness * zoom) - + // Sort into appropriate batch based on edge type if (edge.edgeType === "doc-memory") { - // Doc-memory: Solid thin lines, subtle - dashPattern = [] - connectionColor = colors.connection.memory - opacity = 0.9 - lineWidth = 1 + docMemoryEdges.push(edge) } else if (edge.edgeType === "doc-doc") { - // Doc-doc: Thick dashed lines with strong similarity emphasis - dashPattern = useSimplifiedRendering ? [] : [10, 5] // Solid lines when zoomed out - opacity = Math.max(0, edge.similarity * 0.5) - lineWidth = Math.max(1, edge.similarity * 2) // Thicker for stronger similarity + docDocEdges.push(edge) + } else if (edge.edgeType === "version") { + versionEdges.push(edge) + } + } + }) + + // Helper function to draw a single edge path + const drawEdgePath = (edge: typeof edges[0], sourceNode: GraphNode, targetNode: GraphNode, edgeShouldDim: boolean) => { + const sourceX = sourceNode.x * zoom + panX + const sourceY = sourceNode.y * zoom + panY + const targetX = targetNode.x * zoom + panX + const targetY = targetNode.y * zoom + panY + + // Simplified lines when zoomed out, curved when zoomed in + if (useSimplifiedRendering) { + // Straight lines for performance + ctx.beginPath() + ctx.moveTo(sourceX, sourceY) + ctx.lineTo(targetX, targetY) + ctx.stroke() + } else { + // Regular curved line for doc-memory and doc-doc + const midX = (sourceX + targetX) / 2 + const midY = (sourceY + targetY) / 2 + const dx = targetX - sourceX + const dy = targetY - sourceY + const distance = Math.sqrt(dx * dx + dy * dy) + const controlOffset = + edge.edgeType === "doc-memory" + ? 15 + : Math.min(30, distance * 0.2) + + ctx.beginPath() + ctx.moveTo(sourceX, sourceY) + ctx.quadraticCurveTo( + midX + controlOffset * (dy / distance), + midY - controlOffset * (dx / distance), + targetX, + targetY, + ) + ctx.stroke() + } + } + + // Smooth edge opacity: interpolate between full and 0.05 (dimmed) + const edgeDimOpacity = 1 - (dimProgress.current * 0.95) + + // BATCH 1: Draw all doc-memory edges together + if (docMemoryEdges.length > 0) { + ctx.strokeStyle = colors.connection.memory + ctx.lineWidth = 1 + ctx.setLineDash([]) + + docMemoryEdges.forEach((edge) => { + const sourceNode = + typeof edge.source === "string" + ? nodeMap.get(edge.source) + : edge.source + const targetNode = + typeof edge.target === "string" + ? nodeMap.get(edge.target) + : edge.target + + if (sourceNode && targetNode) { + const edgeShouldDim = selectedNodeId !== null && + sourceNode.id !== selectedNodeId && + targetNode.id !== selectedNodeId + const opacity = edgeShouldDim ? edgeDimOpacity : 0.9 + ctx.globalAlpha = opacity + drawEdgePath(edge, sourceNode, targetNode, edgeShouldDim) + } + }) + } + + // BATCH 2: Draw all doc-doc edges together (grouped by similarity strength) + if (docDocEdges.length > 0) { + const dashPattern = useSimplifiedRendering ? [] : [10, 5] + ctx.setLineDash(dashPattern) + + docDocEdges.forEach((edge) => { + const sourceNode = + typeof edge.source === "string" + ? nodeMap.get(edge.source) + : edge.source + const targetNode = + typeof edge.target === "string" + ? nodeMap.get(edge.target) + : edge.target + + if (sourceNode && targetNode) { + const edgeShouldDim = selectedNodeId !== null && + sourceNode.id !== selectedNodeId && + targetNode.id !== selectedNodeId + const opacity = edgeShouldDim ? edgeDimOpacity : Math.max(0, edge.similarity * 0.5) + const lineWidth = Math.max(1, edge.similarity * 2) + + // Set color based on similarity strength + let connectionColor = colors.connection.weak if (edge.similarity > 0.85) connectionColor = colors.connection.strong else if (edge.similarity > 0.725) connectionColor = colors.connection.medium - } else if (edge.edgeType === "version") { - // Version chains: Double line effect with relation-specific colors - dashPattern = [] - connectionColor = edge.color || colors.relations.updates - opacity = 0.8 - lineWidth = 2 + + ctx.strokeStyle = connectionColor + ctx.lineWidth = lineWidth + ctx.globalAlpha = opacity + drawEdgePath(edge, sourceNode, targetNode, edgeShouldDim) } + }) + } - ctx.strokeStyle = connectionColor - ctx.lineWidth = lineWidth - ctx.globalAlpha = opacity - ctx.setLineDash(dashPattern) + // BATCH 3: Draw all version edges together + if (versionEdges.length > 0) { + ctx.setLineDash([]) + + versionEdges.forEach((edge) => { + const sourceNode = + typeof edge.source === "string" + ? nodeMap.get(edge.source) + : edge.source + const targetNode = + typeof edge.target === "string" + ? nodeMap.get(edge.target) + : edge.target + + if (sourceNode && targetNode) { + const edgeShouldDim = selectedNodeId !== null && + sourceNode.id !== selectedNodeId && + targetNode.id !== selectedNodeId + const opacity = edgeShouldDim ? edgeDimOpacity : 0.8 + const connectionColor = edge.color || colors.relations.updates + + const sourceX = sourceNode.x * zoom + panX + const sourceY = sourceNode.y * zoom + panY + const targetX = targetNode.x * zoom + panX + const targetY = targetNode.y * zoom + panY - if (edge.edgeType === "version") { // Special double-line rendering for version chains + ctx.strokeStyle = connectionColor + // First line (outer) ctx.lineWidth = 3 ctx.globalAlpha = opacity * 0.3 @@ -269,45 +509,12 @@ export const GraphCanvas = memo<GraphCanvasProps>( ctx.moveTo(sourceX, sourceY) ctx.lineTo(targetX, targetY) ctx.stroke() - } else { - // Simplified lines when zoomed out, curved when zoomed in - if (useSimplifiedRendering) { - // Straight lines for performance - ctx.beginPath() - ctx.moveTo(sourceX, sourceY) - ctx.lineTo(targetX, targetY) - ctx.stroke() - } else { - // Regular curved line for doc-memory and doc-doc - const midX = (sourceX + targetX) / 2 - const midY = (sourceY + targetY) / 2 - const dx = targetX - sourceX - const dy = targetY - sourceY - const distance = Math.sqrt(dx * dx + dy * dy) - const controlOffset = - edge.edgeType === "doc-memory" - ? 15 - : Math.min(30, distance * 0.2) - ctx.beginPath() - ctx.moveTo(sourceX, sourceY) - ctx.quadraticCurveTo( - midX + controlOffset * (dy / distance), - midY - controlOffset * (dx / distance), - targetX, - targetY, - ) - ctx.stroke() - } - } - - // Subtle arrow head for version edges - if (edge.edgeType === "version") { + // Subtle arrow head const angle = Math.atan2(targetY - sourceY, targetX - sourceX) - const arrowLength = Math.max(6, 8 * zoom) // Shorter, more subtle + const arrowLength = Math.max(6, 8 * zoom) const arrowWidth = Math.max(8, 12 * zoom) - // Calculate arrow position offset from node edge const nodeRadius = (targetNode.size * zoom) / 2 const offsetDistance = nodeRadius + 2 const arrowX = targetX - Math.cos(angle) * offsetDistance @@ -316,9 +523,7 @@ export const GraphCanvas = memo<GraphCanvasProps>( ctx.save() ctx.translate(arrowX, arrowY) ctx.rotate(angle) - ctx.setLineDash([]) - // Simple outlined arrow (not filled) ctx.strokeStyle = connectionColor ctx.lineWidth = Math.max(1, 1.5 * zoom) ctx.globalAlpha = opacity @@ -332,8 +537,8 @@ export const GraphCanvas = memo<GraphCanvasProps>( ctx.restore() } - } - }) + }) + } ctx.globalAlpha = 1 ctx.setLineDash([]) @@ -360,6 +565,10 @@ export const GraphCanvas = memo<GraphCanvasProps>( const isHovered = currentHoveredNode.current === node.id const isDragging = node.isDragging + const isSelected = selectedNodeId === node.id + const shouldDim = selectedNodeId !== null && !isSelected + // Smooth opacity: interpolate between 1 (full) and 0.1 (dimmed) based on animation progress + const nodeOpacity = shouldDim ? 1 - (dimProgress.current * 0.9) : 1 const isHighlightedDocument = (() => { if (node.type !== "document" || highlightSet.size === 0) return false const doc = node.data as DocumentWithMemories @@ -378,7 +587,7 @@ export const GraphCanvas = memo<GraphCanvasProps>( : isHovered ? colors.document.secondary : colors.document.primary - ctx.globalAlpha = 1 + ctx.globalAlpha = nodeOpacity // Enhanced border with subtle glow ctx.strokeStyle = isDragging @@ -423,7 +632,9 @@ export const GraphCanvas = memo<GraphCanvasProps>( ctx.strokeStyle = colors.accent.primary ctx.lineWidth = 3 ctx.setLineDash([6, 4]) - const ringPadding = 10 + // Add equal padding on all sides (15% of average dimension) + const avgDimension = (docWidth + docHeight) / 2 + const ringPadding = avgDimension * 0.1 ctx.beginPath() ctx.roundRect( screenX - docWidth / 2 - ringPadding, @@ -436,6 +647,21 @@ export const GraphCanvas = memo<GraphCanvasProps>( ctx.setLineDash([]) ctx.restore() } + + // Draw document type icon (centered) + if (!useSimplifiedRendering) { + const doc = node.data as DocumentWithMemories + const iconSize = docHeight * 0.4 // Icon size relative to card height + + drawDocumentIcon( + ctx, + screenX, + screenY, + iconSize, + doc.type || "text", + "rgba(255, 255, 255, 0.8)", + ) + } } else { // Enhanced memory styling with status indicators const mem = node.data as MemoryEntry @@ -484,7 +710,7 @@ export const GraphCanvas = memo<GraphCanvasProps>( const radius = nodeSize / 2 ctx.fillStyle = fillColor - ctx.globalAlpha = isLatest ? 1 : 0.4 + ctx.globalAlpha = shouldDim ? nodeOpacity : (isLatest ? 1 : 0.4) ctx.strokeStyle = borderColor ctx.lineWidth = isDragging ? 3 : isHovered ? 2 : 1.5 @@ -571,18 +797,23 @@ export const GraphCanvas = memo<GraphCanvasProps>( ctx.globalAlpha = 0.6 ctx.beginPath() - const glowSize = nodeSize * 0.7 if (node.type === "document") { + // Use actual document dimensions for glow + const docWidth = nodeSize * 1.4 + const docHeight = nodeSize * 0.9 + // Make glow 10% larger than document + const avgDimension = (docWidth + docHeight) / 2 + const glowPadding = avgDimension * 0.1 ctx.roundRect( - screenX - glowSize, - screenY - glowSize / 1.4, - glowSize * 2, - glowSize * 1.4, + screenX - docWidth / 2 - glowPadding, + screenY - docHeight / 2 - glowPadding, + docWidth + glowPadding * 2, + docHeight + glowPadding * 2, 15, ) } else { // Hexagonal glow for memory nodes - const glowRadius = glowSize + const glowRadius = nodeSize * 0.7 const sides = 6 for (let i = 0; i < sides; i++) { const angle = (i * 2 * Math.PI) / sides - Math.PI / 2 @@ -602,21 +833,33 @@ export const GraphCanvas = memo<GraphCanvasProps>( }) ctx.globalAlpha = 1 - }, [nodes, edges, panX, panY, zoom, width, height, highlightDocumentIds]) + }, [nodes, edges, panX, panY, zoom, width, height, highlightDocumentIds, nodeMap]) - // Change-based rendering instead of continuous animation - const lastRenderParams = useRef<string>("") + // Hybrid rendering: continuous when simulation active, change-based when idle + const lastRenderParams = useRef<number>(0) // Create a render key that changes when visual state changes + // Optimized: use cheap hash instead of building long strings const renderKey = useMemo(() => { - const nodePositions = nodes - .map( - (n) => - `${n.id}:${n.x}:${n.y}:${n.isDragging ? "1" : "0"}:${currentHoveredNode.current === n.id ? "1" : "0"}`, - ) - .join("|") - const highlightKey = (highlightDocumentIds ?? []).join("|") - return `${nodePositions}-${edges.length}-${panX}-${panY}-${zoom}-${width}-${height}-${highlightKey}` + // Hash node positions to a single number (cheaper than string concatenation) + const positionHash = nodes.reduce((hash, n) => { + // Round to 1 decimal to avoid unnecessary re-renders from tiny movements + const x = Math.round(n.x * 10) + const y = Math.round(n.y * 10) + const dragging = n.isDragging ? 1 : 0 + const hovered = currentHoveredNode.current === n.id ? 1 : 0 + // Simple XOR hash (fast and sufficient for change detection) + return hash ^ (x + y + dragging + hovered) + }, 0) + + const highlightHash = (highlightDocumentIds ?? []).reduce((hash, id) => { + return hash ^ id.length + }, 0) + + // Combine all factors into a single number + return positionHash ^ edges.length ^ + Math.round(panX) ^ Math.round(panY) ^ + Math.round(zoom * 100) ^ width ^ height ^ highlightHash }, [ nodes, edges.length, @@ -628,13 +871,28 @@ export const GraphCanvas = memo<GraphCanvasProps>( highlightDocumentIds, ]) - // Only render when something actually changed + // Render based on simulation state useEffect(() => { + if (isSimulationActive) { + // Continuous rendering during physics simulation + const renderLoop = () => { + render() + animationRef.current = requestAnimationFrame(renderLoop) + } + renderLoop() + + return () => { + if (animationRef.current) { + cancelAnimationFrame(animationRef.current) + } + } + } + // Change-based rendering when simulation is idle if (renderKey !== lastRenderParams.current) { lastRenderParams.current = renderKey render() } - }, [renderKey, render]) + }, [isSimulationActive, renderKey, render]) // Cleanup any existing animation frames useEffect(() => { @@ -699,21 +957,33 @@ export const GraphCanvas = memo<GraphCanvasProps>( const canvas = canvasRef.current if (!canvas) return - // upscale backing store + // Maximum safe canvas size (most browsers support up to 16384px) + const MAX_CANVAS_SIZE = 16384 + + // Calculate effective DPR that keeps us within safe limits + // Prevent division by zero by checking for valid dimensions + const maxDpr = width > 0 && height > 0 + ? Math.min( + MAX_CANVAS_SIZE / width, + MAX_CANVAS_SIZE / height, + dpr + ) + : dpr + + // upscale backing store with clamped dimensions canvas.style.width = `${width}px` canvas.style.height = `${height}px` - canvas.width = width * dpr - canvas.height = height * dpr + canvas.width = Math.min(width * maxDpr, MAX_CANVAS_SIZE) + canvas.height = Math.min(height * maxDpr, MAX_CANVAS_SIZE) const ctx = canvas.getContext("2d") - ctx?.scale(dpr, dpr) + ctx?.scale(maxDpr, maxDpr) }, [width, height, dpr]) // ----------------------------------------------------------------------- return ( <canvas className={canvasWrapper} - height={height} onClick={handleClick} onDoubleClick={onDoubleClick} onMouseDown={handleMouseDown} @@ -751,10 +1021,9 @@ export const GraphCanvas = memo<GraphCanvasProps>( userSelect: "none", WebkitUserSelect: "none", }} - width={width} /> ) }, ) -GraphCanvas.displayName = "GraphCanvas" +GraphCanvas.displayName = "GraphCanvas"
\ No newline at end of file diff --git a/packages/memory-graph/src/components/legend.css.ts b/packages/memory-graph/src/components/legend.css.ts index 823edc75..120afa49 100644 --- a/packages/memory-graph/src/components/legend.css.ts +++ b/packages/memory-graph/src/components/legend.css.ts @@ -213,48 +213,66 @@ export const legendText = style({ /** * Shape styles */ -export const hexagon = style({ - clipPath: "polygon(50% 0%, 93% 25%, 93% 75%, 50% 100%, 7% 75%, 7% 25%)", -}) - export const documentNode = style({ width: "1rem", height: "0.75rem", - background: "rgba(255, 255, 255, 0.08)", - border: "1px solid rgba(255, 255, 255, 0.25)", + background: "rgba(255, 255, 255, 0.21)", + border: "1px solid rgba(255, 255, 255, 0.6)", borderRadius: themeContract.radii.sm, flexShrink: 0, }) -export const memoryNode = style([ - hexagon, - { - width: "0.75rem", - height: "0.75rem", - background: "rgba(147, 197, 253, 0.1)", - border: "1px solid rgba(147, 197, 253, 0.35)", - flexShrink: 0, - }, -]) +// Hexagon shapes using SVG background (matching graph's flat-top hexagon) +// Points calculated: angle = (i * 2π / 6) - π/2, center (6,6), radius 4.5 +const hexagonPoints = "6,1.5 10.4,3.75 10.4,8.25 6,10.5 1.6,8.25 1.6,3.75" -export const memoryNodeOlder = style([ - memoryNode, - { - opacity: 0.4, - }, -]) - -export const forgottenNode = style([ - hexagon, - { - width: "0.75rem", - height: "0.75rem", - background: "rgba(239, 68, 68, 0.3)", - border: "1px solid rgba(239, 68, 68, 0.8)", - position: "relative", - flexShrink: 0, - }, -]) +export const memoryNode = style({ + width: "1rem", + height: "1rem", + flexShrink: 0, + backgroundImage: `url("data:image/svg+xml,%3Csvg viewBox='0 0 12 12' xmlns='http://www.w3.org/2000/svg'%3E%3Cpolygon points='${hexagonPoints}' fill='rgba(147,197,253,0.21)' stroke='rgba(147,196,253,0.6)' stroke-width='1'/%3E%3C/svg%3E")`, + backgroundSize: "contain", + backgroundRepeat: "no-repeat", +}) + +export const memoryNodeOlder = style({ + opacity: 0.4, + width: "1rem", + height: "1rem", + flexShrink: 0, + backgroundImage: `url("data:image/svg+xml,%3Csvg viewBox='0 0 12 12' xmlns='http://www.w3.org/2000/svg'%3E%3Cpolygon points='${hexagonPoints}' fill='rgba(147,197,253,0.21)' stroke='rgba(147,196,253,0.6)' stroke-width='1'/%3E%3C/svg%3E")`, + backgroundSize: "contain", + backgroundRepeat: "no-repeat", +}) + +export const forgottenNode = style({ + width: "1rem", + height: "1rem", + flexShrink: 0, + position: "relative", + backgroundImage: `url("data:image/svg+xml,%3Csvg viewBox='0 0 12 12' xmlns='http://www.w3.org/2000/svg'%3E%3Cpolygon points='${hexagonPoints}' fill='rgba(239,68,68,0.3)' stroke='rgba(239,68,68,0.8)' stroke-width='1'/%3E%3C/svg%3E")`, + backgroundSize: "contain", + backgroundRepeat: "no-repeat", +}) + +export const expiringNode = style({ + width: "1rem", + height: "1rem", + flexShrink: 0, + backgroundImage: `url("data:image/svg+xml,%3Csvg viewBox='0 0 12 12' xmlns='http://www.w3.org/2000/svg'%3E%3Cpolygon points='${hexagonPoints}' fill='rgba(147,197,253,0.1)' stroke='rgb(245,158,11)' stroke-width='1.5'/%3E%3C/svg%3E")`, + backgroundSize: "contain", + backgroundRepeat: "no-repeat", +}) + +export const newNode = style({ + width: "1rem", + height: "1rem", + flexShrink: 0, + position: "relative", + backgroundImage: `url("data:image/svg+xml,%3Csvg viewBox='0 0 12 12' xmlns='http://www.w3.org/2000/svg'%3E%3Cpolygon points='${hexagonPoints}' fill='rgba(147,197,253,0.1)' stroke='rgb(16,185,129)' stroke-width='1.5'/%3E%3C/svg%3E")`, + backgroundSize: "contain", + backgroundRepeat: "no-repeat", +}) export const forgottenIcon = style({ position: "absolute", @@ -265,31 +283,9 @@ export const forgottenIcon = style({ color: "rgb(248, 113, 113)", fontSize: themeContract.typography.fontSize.xs, lineHeight: "1", + pointerEvents: "none", }) -export const expiringNode = style([ - hexagon, - { - width: "0.75rem", - height: "0.75rem", - background: "rgba(147, 197, 253, 0.1)", - border: "2px solid rgb(245, 158, 11)", - flexShrink: 0, - }, -]) - -export const newNode = style([ - hexagon, - { - width: "0.75rem", - height: "0.75rem", - background: "rgba(147, 197, 253, 0.1)", - border: "2px solid rgb(16, 185, 129)", - position: "relative", - flexShrink: 0, - }, -]) - export const newBadge = style({ position: "absolute", top: "-0.25rem", @@ -303,14 +299,14 @@ export const newBadge = style({ export const connectionLine = style({ width: "1rem", height: 0, - borderTop: "1px solid rgb(148, 163, 184)", + borderTop: "1px solid rgb(148, 163, 184, 0.5)", flexShrink: 0, }) export const similarityLine = style({ width: "1rem", height: 0, - borderTop: "2px dashed rgb(148, 163, 184)", + borderTop: "2px dashed rgba(35, 189, 255, 0.6)", flexShrink: 0, }) @@ -325,7 +321,7 @@ export const weakSimilarity = style({ width: "0.75rem", height: "0.75rem", borderRadius: themeContract.radii.full, - background: "rgba(148, 163, 184, 0.2)", + background: "rgba(79, 255, 226, 0.3)", flexShrink: 0, }) @@ -333,7 +329,7 @@ export const strongSimilarity = style({ width: "0.75rem", height: "0.75rem", borderRadius: themeContract.radii.full, - background: "rgba(148, 163, 184, 0.6)", + background: "rgba(79, 255, 226, 0.7)", flexShrink: 0, }) diff --git a/packages/memory-graph/src/components/memory-graph.tsx b/packages/memory-graph/src/components/memory-graph.tsx index 8f356d2f..b8dd493d 100644 --- a/packages/memory-graph/src/components/memory-graph.tsx +++ b/packages/memory-graph/src/components/memory-graph.tsx @@ -2,15 +2,17 @@ import { GlassMenuEffect } from "@/ui/glass-effect" import { AnimatePresence } from "motion/react" -import { useCallback, useEffect, useMemo, useRef, useState } from "react" +import { useCallback, useEffect, useMemo, useReducer, useRef, useState } from "react" import { GraphCanvas } from "./graph-canvas" import { useGraphData } from "@/hooks/use-graph-data" import { useGraphInteractions } from "@/hooks/use-graph-interactions" +import { useForceSimulation } from "@/hooks/use-force-simulation" import { injectStyles } from "@/lib/inject-styles" import { Legend } from "./legend" import { LoadingIndicator } from "./loading-indicator" import { NavigationControls } from "./navigation-controls" import { NodeDetailPanel } from "./node-detail-panel" +import { NodePopover } from "./node-popover" import { SpacesDropdown } from "./spaces-dropdown" import * as styles from "./memory-graph.css" import { defaultTheme } from "@/styles/theme.css" @@ -37,7 +39,12 @@ export const MemoryGraph = ({ selectedSpace: externalSelectedSpace, onSpaceChange: externalOnSpaceChange, memoryLimit, + maxNodes, isExperimental, + // Slideshow control + isSlideshowActive = false, + onSlideshowNodeChange, + onSlideshowStop, }: MemoryGraphProps) => { // Inject styles on first render (client-side only) useEffect(() => { @@ -126,6 +133,31 @@ export const MemoryGraph = ({ nodePositions, draggingNodeId, memoryLimit, + maxNodes, + ) + + // State to trigger re-renders when simulation ticks + const [, forceRender] = useReducer((x: number) => x + 1, 0) + + // Track drag state for physics integration + const dragStateRef = useRef<{ + nodeId: string | null + startX: number + startY: number + nodeStartX: number + nodeStartY: number + }>({ nodeId: null, startX: 0, startY: 0, nodeStartX: 0, nodeStartY: 0 }) + + // Force simulation - only runs during interactions (drag) + const forceSimulation = useForceSimulation( + nodes, + edges, + () => { + // On each tick, trigger a re-render + // D3 directly mutates node.x and node.y + forceRender() + }, + true, // enabled ) // Auto-fit once per unique highlight set to show the full graph for context @@ -240,12 +272,91 @@ export const MemoryGraph = ({ } }, []) - // Enhanced node drag start that includes nodes data + // Physics-enabled node drag start const handleNodeDragStartWithNodes = useCallback( (nodeId: string, e: React.MouseEvent) => { + // Find the node being dragged + const node = nodes.find((n) => n.id === nodeId) + if (node) { + // Store drag start state + dragStateRef.current = { + nodeId, + startX: e.clientX, + startY: e.clientY, + nodeStartX: node.x, + nodeStartY: node.y, + } + + // Pin the node at its current position (d3-force pattern) + node.fx = node.x + node.fy = node.y + + // Reheat simulation immediately (like d3 reference code) + forceSimulation.reheat() + } + + // Set dragging state (still need this for visual feedback) handleNodeDragStart(nodeId, e, nodes) }, - [handleNodeDragStart, nodes], + [handleNodeDragStart, nodes, forceSimulation], + ) + + // Physics-enabled node drag move + const handleNodeDragMoveWithNodes = useCallback( + (e: React.MouseEvent) => { + if (draggingNodeId && dragStateRef.current.nodeId === draggingNodeId) { + // Update the fixed position during drag (this is what d3 uses) + const node = nodes.find((n) => n.id === draggingNodeId) + if (node) { + // Calculate new position based on drag delta + const deltaX = (e.clientX - dragStateRef.current.startX) / zoom + const deltaY = (e.clientY - dragStateRef.current.startY) / zoom + + // Update subject position (matches d3 reference code pattern) + // Only update fx/fy, let simulation handle x/y + node.fx = dragStateRef.current.nodeStartX + deltaX + node.fy = dragStateRef.current.nodeStartY + deltaY + } + } + }, + [nodes, draggingNodeId, zoom], + ) + + // Physics-enabled node drag end + const handleNodeDragEndWithPhysics = useCallback(() => { + if (draggingNodeId) { + // Unpin the node (allow physics to take over) - matches d3 reference code + const node = nodes.find((n) => n.id === draggingNodeId) + if (node) { + node.fx = null + node.fy = null + } + + // Cool down the simulation (restore target alpha to 0) + forceSimulation.coolDown() + + // Reset drag state + dragStateRef.current = { + nodeId: null, + startX: 0, + startY: 0, + nodeStartX: 0, + nodeStartY: 0, + } + } + + // Call original handler to clear dragging state + handleNodeDragEnd() + }, [draggingNodeId, nodes, forceSimulation, handleNodeDragEnd]) + + // Physics-aware node click - let simulation continue naturally + const handleNodeClickWithPhysics = useCallback( + (nodeId: string) => { + // Just call original handler to update selected node state + // Don't stop the simulation - let it cool down naturally + handleNodeClick(nodeId) + }, + [handleNodeClick], ) // Navigation callbacks @@ -300,6 +411,54 @@ export const MemoryGraph = ({ return nodes.find((n) => n.id === selectedNode) || null }, [selectedNode, nodes]) + // Calculate popover position (memoized for performance) + const popoverPosition = useMemo(() => { + if (!selectedNodeData) return null + + // Calculate screen position of the node + const screenX = selectedNodeData.x * zoom + panX + const screenY = selectedNodeData.y * zoom + panY + + // Popover dimensions (estimated) + const popoverWidth = 320 + const popoverHeight = 400 + const padding = 16 + + // Calculate node dimensions to position popover with proper gap + const nodeSize = selectedNodeData.size * zoom + const nodeWidth = selectedNodeData.type === "document" ? nodeSize * 1.4 : nodeSize + const nodeHeight = selectedNodeData.type === "document" ? nodeSize * 0.9 : nodeSize + const gap = 20 // Gap between node and popover + + // Smart positioning: flip to other side if would go off-screen + let popoverX = screenX + nodeWidth / 2 + gap + let popoverY = screenY - popoverHeight / 2 + + // Check right edge + if (popoverX + popoverWidth > containerSize.width - padding) { + // Flip to left side of node + popoverX = screenX - nodeWidth / 2 - gap - popoverWidth + } + + // Check left edge + if (popoverX < padding) { + popoverX = padding + } + + // Check bottom edge + if (popoverY + popoverHeight > containerSize.height - padding) { + // Move up + popoverY = containerSize.height - popoverHeight - padding + } + + // Check top edge + if (popoverY < padding) { + popoverY = padding + } + + return { x: popoverX, y: popoverY } + }, [selectedNodeData, zoom, panX, panY, containerSize.width, containerSize.height]) + // Viewport-based loading: load more when most documents are visible (optional) const checkAndLoadMore = useCallback(() => { if ( @@ -378,6 +537,125 @@ export const MemoryGraph = ({ } }, [data, hasMore, throttledCheckAndLoadMore, autoLoadOnViewport]) + // Slideshow logic - simulate actual node clicks with physics + const slideshowIntervalRef = useRef<NodeJS.Timeout | null>(null) + const physicsTimeoutRef = useRef<NodeJS.Timeout | null>(null) + const lastSelectedIndexRef = useRef<number>(-1) + const isSlideshowActiveRef = useRef(isSlideshowActive) + + // Update slideshow active ref + useEffect(() => { + isSlideshowActiveRef.current = isSlideshowActive + }, [isSlideshowActive]) + + // Use refs to store current values without triggering re-renders + const nodesRef = useRef(nodes) + const handleNodeClickRef = useRef(handleNodeClick) + const centerViewportOnRef = useRef(centerViewportOn) + const containerSizeRef = useRef(containerSize) + const onSlideshowNodeChangeRef = useRef(onSlideshowNodeChange) + const forceSimulationRef = useRef(forceSimulation) + + // Update refs when values change + useEffect(() => { + nodesRef.current = nodes + handleNodeClickRef.current = handleNodeClick + centerViewportOnRef.current = centerViewportOn + containerSizeRef.current = containerSize + onSlideshowNodeChangeRef.current = onSlideshowNodeChange + forceSimulationRef.current = forceSimulation + }, [nodes, handleNodeClick, centerViewportOn, containerSize, onSlideshowNodeChange, forceSimulation]) + + useEffect(() => { + // Clear any existing interval and timeout when isSlideshowActive changes + if (slideshowIntervalRef.current) { + clearInterval(slideshowIntervalRef.current) + slideshowIntervalRef.current = null + } + if (physicsTimeoutRef.current) { + clearTimeout(physicsTimeoutRef.current) + physicsTimeoutRef.current = null + } + + if (!isSlideshowActive) { + // Close the popover when stopping slideshow + setSelectedNode(null) + // Explicitly cool down physics simulation in case timeout hasn't fired yet + forceSimulation.coolDown() + return + } + + // Select a random node (avoid selecting the same one twice in a row) + const selectRandomNode = () => { + // Double-check slideshow is still active + if (!isSlideshowActiveRef.current) return + + const currentNodes = nodesRef.current + if (currentNodes.length === 0) return + + let randomIndex: number + // If we have more than one node, avoid selecting the same one + if (currentNodes.length > 1) { + do { + randomIndex = Math.floor(Math.random() * currentNodes.length) + } while (randomIndex === lastSelectedIndexRef.current) + } else { + randomIndex = 0 + } + + lastSelectedIndexRef.current = randomIndex + const randomNode = currentNodes[randomIndex] + + if (randomNode) { + // Smoothly pan to the node first + centerViewportOnRef.current( + randomNode.x, + randomNode.y, + containerSizeRef.current.width, + containerSizeRef.current.height, + ) + + // Simulate the actual node click (triggers dimming and popover) + handleNodeClickRef.current(randomNode.id) + + // Trigger physics animation briefly + forceSimulationRef.current.reheat() + + // Cool down physics after 1 second (cleanup old timeout first) + if (physicsTimeoutRef.current) { + clearTimeout(physicsTimeoutRef.current) + } + physicsTimeoutRef.current = setTimeout(() => { + // Only cool down if slideshow is still active or if this is cleanup + forceSimulationRef.current.coolDown() + physicsTimeoutRef.current = null + }, 1000) + + // Notify parent component + onSlideshowNodeChangeRef.current?.(randomNode.id) + } + } + + // Start immediately + selectRandomNode() + + // Set interval for subsequent selections (3.5 seconds) + slideshowIntervalRef.current = setInterval(() => { + selectRandomNode() + }, 3500) + + return () => { + if (slideshowIntervalRef.current) { + clearInterval(slideshowIntervalRef.current) + slideshowIntervalRef.current = null + } + if (physicsTimeoutRef.current) { + clearTimeout(physicsTimeoutRef.current) + physicsTimeoutRef.current = null + } + } + }, [isSlideshowActive]) // Only depend on isSlideshowActive + if (error) { return ( <div className={styles.errorContainer}> @@ -426,16 +704,17 @@ export const MemoryGraph = ({ variant={variant} /> - {/* Node detail panel */} - <AnimatePresence> - {selectedNodeData && ( - <NodeDetailPanel - node={selectedNodeData} - onClose={() => setSelectedNode(null)} - variant={variant} - /> - )} - </AnimatePresence> + {/* Node popover - positioned near clicked node */} + {selectedNodeData && popoverPosition && ( + <NodePopover + node={selectedNodeData} + x={popoverPosition.x} + y={popoverPosition.y} + onClose={() => setSelectedNode(null)} + containerBounds={containerRef.current?.getBoundingClientRect()} + onBackdropClick={isSlideshowActive ? onSlideshowStop : undefined} + /> + )} {/* Show welcome screen when no memories exist */} {!isLoading && @@ -452,10 +731,11 @@ export const MemoryGraph = ({ height={containerSize.height} nodes={nodes} highlightDocumentIds={highlightsVisible ? highlightDocumentIds : []} + isSimulationActive={forceSimulation.isActive()} onDoubleClick={handleDoubleClick} - onNodeClick={handleNodeClick} - onNodeDragEnd={handleNodeDragEnd} - onNodeDragMove={handleNodeDragMove} + onNodeClick={handleNodeClickWithPhysics} + onNodeDragEnd={handleNodeDragEndWithPhysics} + onNodeDragMove={handleNodeDragMoveWithNodes} onNodeDragStart={handleNodeDragStartWithNodes} onNodeHover={handleNodeHover} onPanEnd={handlePanEnd} @@ -469,6 +749,7 @@ export const MemoryGraph = ({ panY={panY} width={containerSize.width} zoom={zoom} + selectedNodeId={selectedNode} /> )} diff --git a/packages/memory-graph/src/components/node-popover.css.ts b/packages/memory-graph/src/components/node-popover.css.ts new file mode 100644 index 00000000..c758f4b5 --- /dev/null +++ b/packages/memory-graph/src/components/node-popover.css.ts @@ -0,0 +1,176 @@ +import { style } from "@vanilla-extract/css" + +// Backdrop styles +export const backdrop = style({ + position: "fixed", + zIndex: 999, + pointerEvents: "auto", + backgroundColor: "transparent", +}) + +export const backdropFullscreen = style({ + inset: 0, +}) + +// Popover container +export const popoverContainer = style({ + position: "fixed", + background: "rgba(255, 255, 255, 0.05)", + backdropFilter: "blur(12px)", + WebkitBackdropFilter: "blur(12px)", + border: "1px solid rgba(255, 255, 255, 0.25)", + borderRadius: "12px", + padding: "16px", + width: "320px", + zIndex: 1000, + pointerEvents: "auto", + boxShadow: + "0 20px 25px -5px rgb(0 0 0 / 0.3), 0 8px 10px -6px rgb(0 0 0 / 0.3)", +}) + +// Layout +export const contentContainer = style({ + display: "flex", + flexDirection: "column", + gap: "12px", +}) + +export const header = style({ + display: "flex", + alignItems: "center", + justifyContent: "space-between", + marginBottom: "4px", +}) + +export const headerTitle = style({ + display: "flex", + alignItems: "center", + gap: "8px", +}) + +export const headerIcon = style({ + color: "rgba(148, 163, 184, 1)", +}) + +export const headerIconMemory = style({ + color: "rgb(96, 165, 250)", +}) + +export const title = style({ + fontSize: "16px", + fontWeight: "700", + color: "white", + margin: 0, +}) + +// Close button +export const closeButton = style({ + padding: "4px", + background: "transparent", + border: "none", + color: "rgba(148, 163, 184, 1)", + cursor: "pointer", + fontSize: "16px", + lineHeight: "1", + transition: "color 0.2s", + ":hover": { + color: "white", + }, +}) + +// Sections +export const sectionsContainer = style({ + display: "flex", + flexDirection: "column", + gap: "12px", +}) + +export const fieldLabel = style({ + fontSize: "11px", + color: "rgba(148, 163, 184, 0.8)", + textTransform: "uppercase", + letterSpacing: "0.05em", + marginBottom: "4px", +}) + +export const fieldValue = style({ + fontSize: "14px", + color: "rgba(203, 213, 225, 1)", + margin: 0, + lineHeight: "1.4", +}) + +export const summaryValue = style({ + fontSize: "14px", + color: "rgba(203, 213, 225, 1)", + margin: 0, + lineHeight: "1.4", + overflow: "hidden", + display: "-webkit-box", + WebkitLineClamp: 2, + WebkitBoxOrient: "vertical", +}) + +// Link +export const link = style({ + fontSize: "14px", + color: "rgb(129, 140, 248)", + textDecoration: "none", + display: "flex", + alignItems: "center", + gap: "4px", + transition: "color 0.2s", + ":hover": { + color: "rgb(165, 180, 252)", + }, +}) + +// Footer +export const footer = style({ + paddingTop: "12px", + borderTop: "1px solid rgba(71, 85, 105, 0.5)", + display: "flex", + alignItems: "center", + gap: "16px", + fontSize: "12px", + color: "rgba(148, 163, 184, 1)", +}) + +export const footerItem = style({ + display: "flex", + alignItems: "center", + gap: "4px", +}) + +export const footerItemId = style({ + display: "flex", + alignItems: "center", + gap: "4px", + overflow: "hidden", + textOverflow: "ellipsis", + whiteSpace: "nowrap", + flex: 1, +}) + +export const idText = style({ + overflow: "hidden", + textOverflow: "ellipsis", +}) + +// Memory-specific styles +export const forgottenBadge = style({ + marginTop: "8px", + padding: "4px 8px", + background: "rgba(220, 38, 38, 0.15)", + borderRadius: "4px", + fontSize: "12px", + color: "rgba(248, 113, 113, 1)", + display: "inline-block", +}) + +export const expiresText = style({ + fontSize: "12px", + color: "rgba(148, 163, 184, 1)", + margin: "8px 0 0 0", + lineHeight: "1.4", +}) diff --git a/packages/memory-graph/src/components/node-popover.tsx b/packages/memory-graph/src/components/node-popover.tsx new file mode 100644 index 00000000..8c798110 --- /dev/null +++ b/packages/memory-graph/src/components/node-popover.tsx @@ -0,0 +1,280 @@ +"use client" + +import { memo, useEffect } from "react" +import type { GraphNode } from "@/types" +import * as styles from "./node-popover.css" + +export interface NodePopoverProps { + node: GraphNode + x: number // Screen X position + y: number // Screen Y position + onClose: () => void + containerBounds?: DOMRect // Optional container bounds to limit backdrop + onBackdropClick?: () => void // Optional callback when backdrop is clicked +} + +export const NodePopover = memo<NodePopoverProps>(function NodePopover({ + node, + x, + y, + onClose, + containerBounds, + onBackdropClick, +}) { + // Handle Escape key to close popover + useEffect(() => { + const handleKeyDown = (e: KeyboardEvent) => { + if (e.key === "Escape") { + onClose() + } + } + + window.addEventListener("keydown", handleKeyDown) + return () => window.removeEventListener("keydown", handleKeyDown) + }, [onClose]) + + // Calculate backdrop bounds - use container bounds if provided, otherwise full viewport + const backdropStyle = containerBounds + ? { + left: `${containerBounds.left}px`, + top: `${containerBounds.top}px`, + width: `${containerBounds.width}px`, + height: `${containerBounds.height}px`, + } + : undefined + + const backdropClassName = containerBounds + ? styles.backdrop + : `${styles.backdrop} ${styles.backdropFullscreen}` + + const handleBackdropClick = () => { + onBackdropClick?.() + onClose() + } + + return ( + <> + {/* Invisible backdrop to catch clicks outside */} + <div onClick={handleBackdropClick} className={backdropClassName} style={backdropStyle} /> + + {/* Popover content */} + <div + onClick={(e) => e.stopPropagation()} // Prevent closing when clicking inside + className={styles.popoverContainer} + style={{ + left: `${x}px`, + top: `${y}px`, + }} + > + {node.type === "document" ? ( + // Document popover + <div className={styles.contentContainer}> + {/* Header */} + <div className={styles.header}> + <div className={styles.headerTitle}> + <svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round" className={styles.headerIcon}> + <path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"></path> + <polyline points="14 2 14 8 20 8"></polyline> + <line x1="16" y1="13" x2="8" y2="13"></line> + <line x1="16" y1="17" x2="8" y2="17"></line> + <polyline points="10 9 9 9 8 9"></polyline> + </svg> + <h3 className={styles.title}> + Document + </h3> + </div> + <button + type="button" + onClick={onClose} + className={styles.closeButton} + > + × + </button> + </div> + + {/* Sections */} + <div className={styles.sectionsContainer}> + {/* Title */} + <div> + <div className={styles.fieldLabel}> + Title + </div> + <p className={styles.fieldValue}> + {(node.data as any).title || "Untitled Document"} + </p> + </div> + + {/* Summary - truncated to 2 lines */} + {(node.data as any).summary && ( + <div> + <div className={styles.fieldLabel}> + Summary + </div> + <p className={styles.summaryValue}> + {(node.data as any).summary} + </p> + </div> + )} + + {/* Type */} + <div> + <div className={styles.fieldLabel}> + Type + </div> + <p className={styles.fieldValue}> + {(node.data as any).type || "Document"} + </p> + </div> + + {/* Memory Count */} + <div> + <div className={styles.fieldLabel}> + Memory Count + </div> + <p className={styles.fieldValue}> + {(node.data as any).memoryEntries?.length || 0} memories + </p> + </div> + + {/* URL */} + {((node.data as any).url || (node.data as any).customId) && ( + <div> + <div className={styles.fieldLabel}> + URL + </div> + <a + href={(() => { + const doc = node.data as any + if (doc.type === "google_doc" && doc.customId) { + return `https://docs.google.com/document/d/${doc.customId}` + } + if (doc.type === "google_sheet" && doc.customId) { + return `https://docs.google.com/spreadsheets/d/${doc.customId}` + } + if (doc.type === "google_slide" && doc.customId) { + return `https://docs.google.com/presentation/d/${doc.customId}` + } + return doc.url ?? undefined + })()} + target="_blank" + rel="noopener noreferrer" + className={styles.link} + > + <svg width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"> + <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path> + <polyline points="15 3 21 3 21 9"></polyline> + <line x1="10" y1="14" x2="21" y2="3"></line> + </svg> + View Document + </a> + </div> + )} + + {/* Footer with metadata */} + <div className={styles.footer}> + <div className={styles.footerItem}> + <svg width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"> + <rect x="3" y="4" width="18" height="18" rx="2" ry="2"></rect> + <line x1="16" y1="2" x2="16" y2="6"></line> + <line x1="8" y1="2" x2="8" y2="6"></line> + <line x1="3" y1="10" x2="21" y2="10"></line> + </svg> + <span>{new Date((node.data as any).createdAt).toLocaleDateString()}</span> + </div> + <div className={styles.footerItemId}> + <svg width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"> + <line x1="4" y1="9" x2="20" y2="9"></line> + <line x1="4" y1="15" x2="20" y2="15"></line> + <line x1="10" y1="3" x2="8" y2="21"></line> + <line x1="16" y1="3" x2="14" y2="21"></line> + </svg> + <span className={styles.idText}>{node.id}</span> + </div> + </div> + </div> + </div> + ) : ( + // Memory popover + <div className={styles.contentContainer}> + {/* Header */} + <div className={styles.header}> + <div className={styles.headerTitle}> + <svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round" className={styles.headerIconMemory}> + <path d="M9.5 2A2.5 2.5 0 0 1 12 4.5v15a2.5 2.5 0 0 1-4.96.44 2.5 2.5 0 0 1-2.96-3.08 3 3 0 0 1-.34-5.58 2.5 2.5 0 0 1 1.32-4.24 2.5 2.5 0 0 1 1.98-3A2.5 2.5 0 0 1 9.5 2Z"></path> + <path d="M14.5 2A2.5 2.5 0 0 0 12 4.5v15a2.5 2.5 0 0 0 4.96.44 2.5 2.5 0 0 0 2.96-3.08 3 3 0 0 0 .34-5.58 2.5 2.5 0 0 0-1.32-4.24 2.5 2.5 0 0 0-1.98-3A2.5 2.5 0 0 0 14.5 2Z"></path> + </svg> + <h3 className={styles.title}> + Memory + </h3> + </div> + <button + type="button" + onClick={onClose} + className={styles.closeButton} + > + × + </button> + </div> + + {/* Sections */} + <div className={styles.sectionsContainer}> + {/* Memory content */} + <div> + <div className={styles.fieldLabel}> + Memory + </div> + <p className={styles.fieldValue}> + {(node.data as any).memory || (node.data as any).content || "No content"} + </p> + {(node.data as any).isForgotten && ( + <div className={styles.forgottenBadge}> + Forgotten + </div> + )} + {/* Expires (inline with memory if exists) */} + {(node.data as any).forgetAfter && ( + <p className={styles.expiresText}> + Expires: {new Date((node.data as any).forgetAfter).toLocaleDateString()} + {(node.data as any).forgetReason && ` - ${(node.data as any).forgetReason}`} + </p> + )} + </div> + + {/* Space */} + <div> + <div className={styles.fieldLabel}> + Space + </div> + <p className={styles.fieldValue}> + {(node.data as any).spaceId || "Default"} + </p> + </div> + + {/* Footer with metadata */} + <div className={styles.footer}> + <div className={styles.footerItem}> + <svg width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"> + <rect x="3" y="4" width="18" height="18" rx="2" ry="2"></rect> + <line x1="16" y1="2" x2="16" y2="6"></line> + <line x1="8" y1="2" x2="8" y2="6"></line> + <line x1="3" y1="10" x2="21" y2="10"></line> + </svg> + <span>{new Date((node.data as any).createdAt).toLocaleDateString()}</span> + </div> + <div className={styles.footerItemId}> + <svg width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"> + <line x1="4" y1="9" x2="20" y2="9"></line> + <line x1="4" y1="15" x2="20" y2="15"></line> + <line x1="10" y1="3" x2="8" y2="21"></line> + <line x1="16" y1="3" x2="14" y2="21"></line> + </svg> + <span className={styles.idText}>{node.id}</span> + </div> + </div> + </div> + </div> + )} + </div> + </> + ) +}) diff --git a/packages/memory-graph/src/constants.ts b/packages/memory-graph/src/constants.ts index fddfdee5..e6ab4a26 100644 --- a/packages/memory-graph/src/constants.ts +++ b/packages/memory-graph/src/constants.ts @@ -6,24 +6,24 @@ export const colors = { accent: "#252a35", // Card backgrounds }, document: { - primary: "rgba(255, 255, 255, 0.06)", // Subtle glass white - secondary: "rgba(255, 255, 255, 0.12)", // More visible - accent: "rgba(255, 255, 255, 0.18)", // Hover state - border: "rgba(255, 255, 255, 0.25)", // Sharp borders + primary: "rgba(255, 255, 255, 0.21)", // Subtle glass white + secondary: "rgba(255, 255, 255, 0.31)", // More visible + accent: "rgba(255, 255, 255, 0.31)", // Hover state + border: "rgba(255, 255, 255, 0.6)", // Sharp borders glow: "rgba(147, 197, 253, 0.4)", // Blue glow for interaction }, memory: { - primary: "rgba(147, 197, 253, 0.08)", // Subtle glass blue - secondary: "rgba(147, 197, 253, 0.16)", // More visible - accent: "rgba(147, 197, 253, 0.24)", // Hover state - border: "rgba(147, 197, 253, 0.35)", // Sharp borders + primary: "rgba(147, 196, 253, 0.21)", // Subtle glass blue + secondary: "rgba(147, 196, 253, 0.31)", // More visible + accent: "rgba(147, 197, 253, 0.31)", // Hover state + border: "rgba(147, 196, 253, 0.6)", // Sharp borders glow: "rgba(147, 197, 253, 0.5)", // Blue glow for interaction }, connection: { - weak: "rgba(148, 163, 184, 0)", // Very subtle - memory: "rgba(148, 163, 184, 0.3)", // Very subtle - medium: "rgba(148, 163, 184, 0.125)", // Medium visibility - strong: "rgba(148, 163, 184, 0.4)", // Strong connection + weak: "rgba(35, 189, 255, 0.3)", // subtle + memory: "rgba(148, 163, 184, 0.35)", // Very subtle + medium: "rgba(35, 189, 255, 0.6)", // Medium visibility + strong: "rgba(35, 189, 255, 0.9)", // Strong connection }, text: { primary: "#ffffff", // Pure white @@ -59,6 +59,38 @@ export const LAYOUT_CONSTANTS = { memoryClusterRadius: 300, } +// Similarity calculation configuration +export const SIMILARITY_CONFIG = { + threshold: 0.725, // Minimum similarity (72.5%) to create edge + maxComparisonsPerDoc: 10, // k-NN: each doc compares with 10 neighbors (optimized for performance) +} + +// D3-Force simulation configuration +export const FORCE_CONFIG = { + // Link force (spring between connected nodes)simil + linkStrength: { + docMemory: 0.8, // Strong for doc-memory connections + version: 1.0, // Strongest for version chains + docDocBase: 0.3, // Base for doc-doc similarity + }, + linkDistance: 300, // Desired spring length + + // Charge force (repulsion between nodes) + chargeStrength: -1000, // Negative = repulsion, higher magnitude = stronger push + + // Collision force (prevents node overlap) + collisionRadius: { + document: 80, // Collision radius for document nodes + memory: 40, // Collision radius for memory nodes + }, + + // Simulation behavior + alphaDecay: 0.03, // How fast simulation cools down (higher = faster cooldown) + alphaMin: 0.001, // Threshold to stop simulation (when alpha drops below this) + velocityDecay: 0.6, // Friction/damping (0 = no friction, 1 = instant stop) - increased for less movement + alphaTarget: 0.3, // Target alpha when reheating (on drag start) +} + // Graph view settings export const GRAPH_SETTINGS = { console: { @@ -73,6 +105,12 @@ export const GRAPH_SETTINGS = { }, } +// Animation settings +export const ANIMATION = { + // Dim effect duration - shortened for better UX + dimDuration: 1500, // milliseconds +} + // Responsive positioning for different app variants export const POSITIONING = { console: { diff --git a/packages/memory-graph/src/hooks/use-force-simulation.ts b/packages/memory-graph/src/hooks/use-force-simulation.ts new file mode 100644 index 00000000..d409a4b1 --- /dev/null +++ b/packages/memory-graph/src/hooks/use-force-simulation.ts @@ -0,0 +1,180 @@ +"use client" + +import { useEffect, useRef, useCallback } from "react" +import * as d3 from "d3-force" +import { FORCE_CONFIG } from "@/constants" +import type { GraphNode, GraphEdge } from "@/types" + +export interface ForceSimulationControls { + /** The d3 simulation instance */ + simulation: d3.Simulation<GraphNode, GraphEdge> | null + /** Reheat the simulation (call on drag start) */ + reheat: () => void + /** Cool down the simulation (call on drag end) */ + coolDown: () => void + /** Check if simulation is currently active */ + isActive: () => boolean + /** Stop the simulation completely */ + stop: () => void + /** Get current alpha value */ + getAlpha: () => number +} + +/** + * Custom hook to manage d3-force simulation lifecycle + * Simulation only runs during interactions (drag) for performance + */ +export function useForceSimulation( + nodes: GraphNode[], + edges: GraphEdge[], + onTick: () => void, + enabled = true, +): ForceSimulationControls { + const simulationRef = useRef<d3.Simulation<GraphNode, GraphEdge> | null>(null) + + // Initialize simulation ONCE + useEffect(() => { + if (!enabled || nodes.length === 0) { + return + } + + // Only create simulation once + if (!simulationRef.current) { + const simulation = d3 + .forceSimulation<GraphNode>(nodes) + .alphaDecay(FORCE_CONFIG.alphaDecay) + .alphaMin(FORCE_CONFIG.alphaMin) + .velocityDecay(FORCE_CONFIG.velocityDecay) + .on("tick", () => { + // Trigger re-render by calling onTick + // D3 has already mutated node.x and node.y + onTick() + }) + + // Configure forces + // 1. Link force - spring connections between nodes + simulation.force( + "link", + d3 + .forceLink<GraphNode, GraphEdge>(edges) + .id((d) => d.id) + .distance(FORCE_CONFIG.linkDistance) + .strength((link) => { + // Different strength based on edge type + if (link.edgeType === "doc-memory") { + return FORCE_CONFIG.linkStrength.docMemory + } + if (link.edgeType === "version") { + return FORCE_CONFIG.linkStrength.version + } + // doc-doc: variable strength based on similarity + return link.similarity * FORCE_CONFIG.linkStrength.docDocBase + }), + ) + + // 2. Charge force - repulsion between nodes + simulation.force( + "charge", + d3.forceManyBody<GraphNode>().strength(FORCE_CONFIG.chargeStrength), + ) + + // 3. Collision force - prevent node overlap + simulation.force( + "collide", + d3 + .forceCollide<GraphNode>() + .radius((d) => + d.type === "document" + ? FORCE_CONFIG.collisionRadius.document + : FORCE_CONFIG.collisionRadius.memory, + ) + .strength(0.7), + ) + + // 4. forceX and forceY - weak centering forces (like reference code) + simulation.force("x", d3.forceX().strength(0.05)) + simulation.force("y", d3.forceY().strength(0.05)) + + // Store reference + simulationRef.current = simulation + + // Quick pre-settle to avoid initial chaos, then animate the rest + // This gives best of both worlds: fast initial render + smooth settling + simulation.alpha(1) + for (let i = 0; i < 50; ++i) simulation.tick() // Just 50 ticks = ~5-10ms + simulation.alphaTarget(0).restart() // Continue animating to full stability + } + + // Cleanup on unmount + return () => { + if (simulationRef.current) { + simulationRef.current.stop() + simulationRef.current = null + } + } + // Only run on mount/unmount, not when nodes/edges/onTick change + // eslint-disable-next-line react-hooks/exhaustive-deps + }, [enabled]) + + // Update simulation nodes and edges together to prevent race conditions + useEffect(() => { + if (!simulationRef.current) return + + // Update nodes + if (nodes.length > 0) { + simulationRef.current.nodes(nodes) + } + + // Update edges + if (edges.length > 0) { + const linkForce = simulationRef.current.force< + d3.ForceLink<GraphNode, GraphEdge> + >("link") + if (linkForce) { + linkForce.links(edges) + } + } + }, [nodes, edges]) + + // Reheat simulation (called on drag start) + const reheat = useCallback(() => { + if (simulationRef.current) { + simulationRef.current.alphaTarget(FORCE_CONFIG.alphaTarget).restart() + } + }, []) + + // Cool down simulation (called on drag end) + const coolDown = useCallback(() => { + if (simulationRef.current) { + simulationRef.current.alphaTarget(0) + } + }, []) + + // Check if simulation is active + const isActive = useCallback(() => { + if (!simulationRef.current) return false + return simulationRef.current.alpha() > FORCE_CONFIG.alphaMin + }, []) + + // Stop simulation completely + const stop = useCallback(() => { + if (simulationRef.current) { + simulationRef.current.stop() + } + }, []) + + // Get current alpha + const getAlpha = useCallback(() => { + if (!simulationRef.current) return 0 + return simulationRef.current.alpha() + }, []) + + return { + simulation: simulationRef.current, + reheat, + coolDown, + isActive, + stop, + getAlpha, + } +} diff --git a/packages/memory-graph/src/hooks/use-graph-data.ts b/packages/memory-graph/src/hooks/use-graph-data.ts index e605bd73..9bcd0d55 100644 --- a/packages/memory-graph/src/hooks/use-graph-data.ts +++ b/packages/memory-graph/src/hooks/use-graph-data.ts @@ -5,8 +5,8 @@ import { getConnectionVisualProps, getMagicalConnectionColor, } from "@/lib/similarity" -import { useMemo } from "react" -import { colors, LAYOUT_CONSTANTS } from "@/constants" +import { useMemo, useRef, useEffect } from "react" +import { colors, LAYOUT_CONSTANTS, SIMILARITY_CONFIG } from "@/constants" import type { DocumentsResponse, DocumentWithMemories, @@ -19,19 +19,48 @@ import type { export function useGraphData( data: DocumentsResponse | null, selectedSpace: string, - nodePositions: Map<string, { x: number; y: number }>, + nodePositions: Map<string, { x: number; y: number; parentDocId?: string; offsetX?: number; offsetY?: number }>, draggingNodeId: string | null, memoryLimit?: number, + maxNodes?: number, ) { - return useMemo(() => { - if (!data?.documents) return { nodes: [], edges: [] } + // Cache nodes to preserve d3-force mutations (x, y, vx, vy, fx, fy) + const nodeCache = useRef<Map<string, GraphNode>>(new Map()) - const allNodes: GraphNode[] = [] - const allEdges: GraphEdge[] = [] + // Cleanup nodeCache to prevent memory leak + useEffect(() => { + if (!data?.documents) return + + // Build set of current node IDs + const currentNodeIds = new Set<string>() + data.documents.forEach((doc) => { + currentNodeIds.add(doc.id) + doc.memoryEntries.forEach((mem) => { + currentNodeIds.add(`${mem.id}`) + }) + }) + + // Remove stale nodes from cache + for (const [id] of nodeCache.current.entries()) { + if (!currentNodeIds.has(id)) { + nodeCache.current.delete(id) + } + } + }, [data, selectedSpace]) + + // Memo 1: Filter documents by selected space and apply node limits + const filteredDocuments = useMemo(() => { + if (!data?.documents) return [] + + // Sort documents by most recent first + const sortedDocs = [...data.documents].sort((a, b) => { + const dateA = new Date(a.updatedAt || a.createdAt).getTime() + const dateB = new Date(b.updatedAt || b.createdAt).getTime() + return dateB - dateA // Most recent first + }) - // Filter documents that have memories in selected space - // AND limit memories per document when memoryLimit is provided - const filteredDocuments = data.documents + // Filter by space and prepare documents + let processedDocs = sortedDocs .map((doc) => { let memories = selectedSpace === "all" @@ -42,10 +71,17 @@ export function useGraphData( selectedSpace, ) - // Apply memory limit if provided and a specific space is selected - if (selectedSpace !== "all" && memoryLimit && memoryLimit > 0) { - memories = memories.slice(0, memoryLimit) - } + // Sort memories by relevance score (if available) or recency + memories = memories.sort((a, b) => { + // Prioritize sourceRelevanceScore if available + if (a.sourceRelevanceScore != null && b.sourceRelevanceScore != null) { + return b.sourceRelevanceScore - a.sourceRelevanceScore // Higher score first + } + // Fall back to most recent + const dateA = new Date(a.updatedAt || a.createdAt).getTime() + const dateB = new Date(b.updatedAt || b.createdAt).getTime() + return dateB - dateA // Most recent first + }) return { ...doc, @@ -53,6 +89,138 @@ export function useGraphData( } }) + // Apply maxNodes limit using Option B (dynamic cap per document) + if (maxNodes && maxNodes > 0) { + const totalDocs = processedDocs.length + if (totalDocs > 0) { + // Calculate memories per document to stay within maxNodes budget + const memoriesPerDoc = Math.floor(maxNodes / totalDocs) + + // If we need to limit, slice memories for each document + if (memoriesPerDoc > 0) { + let totalNodes = 0 + processedDocs = processedDocs.map((doc) => { + // Limit memories to calculated amount per doc + const limitedMemories = doc.memoryEntries.slice(0, memoriesPerDoc) + totalNodes += limitedMemories.length + return { + ...doc, + memoryEntries: limitedMemories, + } + }) + + // If we still have budget left, distribute remaining nodes to first docs + let remainingBudget = maxNodes - totalNodes + if (remainingBudget > 0) { + for (let i = 0; i < processedDocs.length && remainingBudget > 0; i++) { + const doc = processedDocs[i] + if (!doc) continue + const originalDoc = sortedDocs.find(d => d.id === doc.id) + if (!originalDoc) continue + + const currentMemCount = doc.memoryEntries.length + const originalMemCount = originalDoc.memoryEntries.filter( + m => selectedSpace === "all" || + (m.spaceContainerTag ?? m.spaceId ?? "default") === selectedSpace + ).length + + // Can we add more memories to this doc? + const canAdd = originalMemCount - currentMemCount + if (canAdd > 0) { + const toAdd = Math.min(canAdd, remainingBudget) + const additionalMems = doc.memoryEntries.slice(0, currentMemCount + toAdd) + processedDocs[i] = { + ...doc, + memoryEntries: originalDoc.memoryEntries + .filter(m => selectedSpace === "all" || + (m.spaceContainerTag ?? m.spaceId ?? "default") === selectedSpace) + .sort((a, b) => { + if (a.sourceRelevanceScore != null && b.sourceRelevanceScore != null) { + return b.sourceRelevanceScore - a.sourceRelevanceScore + } + const dateA = new Date(a.updatedAt || a.createdAt).getTime() + const dateB = new Date(b.updatedAt || b.createdAt).getTime() + return dateB - dateA + }) + .slice(0, currentMemCount + toAdd) + } + remainingBudget -= toAdd + } + } + } + } else { + // If memoriesPerDoc is 0, we need to limit the number of documents shown + // Show at least 1 memory per document, up to maxNodes documents + processedDocs = processedDocs.slice(0, maxNodes).map((doc) => ({ + ...doc, + memoryEntries: doc.memoryEntries.slice(0, 1), + })) + } + } + } + // Apply legacy memoryLimit if provided and a specific space is selected + else if (selectedSpace !== "all" && memoryLimit && memoryLimit > 0) { + processedDocs = processedDocs.map((doc) => ({ + ...doc, + memoryEntries: doc.memoryEntries.slice(0, memoryLimit), + })) + } + + return processedDocs + }, [data, selectedSpace, memoryLimit, maxNodes]) + + // Memo 2: Calculate similarity edges using k-NN approach + const similarityEdges = useMemo(() => { + const edges: GraphEdge[] = [] + + // k-NN: Each document compares with k neighbors (configurable) + const { maxComparisonsPerDoc, threshold } = SIMILARITY_CONFIG + + for (let i = 0; i < filteredDocuments.length; i++) { + const docI = filteredDocuments[i] + if (!docI) continue + + // Only compare with next k documents (k-nearest neighbors approach) + const endIdx = Math.min( + i + maxComparisonsPerDoc + 1, + filteredDocuments.length, + ) + + for (let j = i + 1; j < endIdx; j++) { + const docJ = filteredDocuments[j] + if (!docJ) continue + + const sim = calculateSemanticSimilarity( + docI.summaryEmbedding ? Array.from(docI.summaryEmbedding) : null, + docJ.summaryEmbedding ? Array.from(docJ.summaryEmbedding) : null, + ) + + if (sim > threshold) { + edges.push({ + id: `doc-doc-${docI.id}-${docJ.id}`, + source: docI.id, + target: docJ.id, + similarity: sim, + visualProps: getConnectionVisualProps(sim), + color: getMagicalConnectionColor(sim, 200), + edgeType: "doc-doc", + }) + } + } + } + + return edges + }, [filteredDocuments]) + + // Memo 3: Build full graph data (nodes + edges) + return useMemo(() => { + if (!data?.documents || filteredDocuments.length === 0) { + return { nodes: [], edges: [] } + } + + const allNodes: GraphNode[] = [] + const allEdges: GraphEdge[] = [] + // Group documents by space for better clustering const documentsBySpace = new Map<string, typeof filteredDocuments>() filteredDocuments.forEach((doc) => { @@ -70,7 +238,7 @@ export function useGraphData( }) // Enhanced Layout with Space Separation - const { centerX, centerY, clusterRadius, spaceSpacing, documentSpacing } = + const { centerX, centerY, clusterRadius } = LAYOUT_CONSTANTS /* 1. Build DOCUMENT nodes with space-aware clustering */ @@ -78,104 +246,55 @@ export function useGraphData( let spaceIndex = 0 documentsBySpace.forEach((spaceDocs) => { - const spaceAngle = (spaceIndex / documentsBySpace.size) * Math.PI * 2 - const spaceOffsetX = Math.cos(spaceAngle) * spaceSpacing - const spaceOffsetY = Math.sin(spaceAngle) * spaceSpacing - const spaceCenterX = centerX + spaceOffsetX - const spaceCenterY = centerY + spaceOffsetY - spaceDocs.forEach((doc, docIndex) => { - // Create proper circular layout with concentric rings - const docsPerRing = 6 // Start with 6 docs in inner ring - let currentRing = 0 - let docsInCurrentRing = docsPerRing - let totalDocsInPreviousRings = 0 - - // Find which ring this document belongs to - while (totalDocsInPreviousRings + docsInCurrentRing <= docIndex) { - totalDocsInPreviousRings += docsInCurrentRing - currentRing++ - docsInCurrentRing = docsPerRing + currentRing * 4 // Each ring has more docs - } - - // Position within the ring - const positionInRing = docIndex - totalDocsInPreviousRings - const angleInRing = (positionInRing / docsInCurrentRing) * Math.PI * 2 + // Simple grid-like layout that physics will naturally organize + // Start documents near the center with some random offset + const gridSize = Math.ceil(Math.sqrt(spaceDocs.length)) + const row = Math.floor(docIndex / gridSize) + const col = docIndex % gridSize - // Radius increases significantly with each ring - const baseRadius = documentSpacing * 0.8 - const radius = - currentRing === 0 - ? baseRadius - : baseRadius + currentRing * documentSpacing * 1.2 - - const defaultX = spaceCenterX + Math.cos(angleInRing) * radius - const defaultY = spaceCenterY + Math.sin(angleInRing) * radius + // Loose grid spacing - physics will organize it better + const spacing = 200 + const defaultX = centerX + (col - gridSize / 2) * spacing + (Math.random() - 0.5) * 50 + const defaultY = centerY + (row - gridSize / 2) * spacing + (Math.random() - 0.5) * 50 const customPos = nodePositions.get(doc.id) - documentNodes.push({ - id: doc.id, - type: "document", - x: customPos?.x ?? defaultX, - y: customPos?.y ?? defaultY, - data: doc, - size: 58, - color: colors.document.primary, - isHovered: false, - isDragging: draggingNodeId === doc.id, - } satisfies GraphNode) + // Check if node exists in cache (preserves d3-force mutations) + let node = nodeCache.current.get(doc.id) + if (node) { + // Update existing node's data, preserve physics properties (x, y, vx, vy, fx, fy) + node.data = doc + node.isDragging = draggingNodeId === doc.id + // Don't reset x/y - they're managed by d3-force + } else { + // Create new node with initial position + node = { + id: doc.id, + type: "document", + x: customPos?.x ?? defaultX, + y: customPos?.y ?? defaultY, + data: doc, + size: 58, + color: colors.document.primary, + isHovered: false, + isDragging: draggingNodeId === doc.id, + } satisfies GraphNode + nodeCache.current.set(doc.id, node) + } + + documentNodes.push(node) }) spaceIndex++ }) - /* 2. Gentle document collision avoidance with dampening */ - const minDocDist = LAYOUT_CONSTANTS.minDocDist - - // Reduced iterations and gentler repulsion for smoother movement - for (let iter = 0; iter < 2; iter++) { - documentNodes.forEach((nodeA) => { - documentNodes.forEach((nodeB) => { - if (nodeA.id >= nodeB.id) return - - // Only repel documents in the same space - const spaceA = - (nodeA.data as DocumentWithMemories).memoryEntries[0] - ?.spaceContainerTag ?? - (nodeA.data as DocumentWithMemories).memoryEntries[0]?.spaceId ?? - "default" - const spaceB = - (nodeB.data as DocumentWithMemories).memoryEntries[0] - ?.spaceContainerTag ?? - (nodeB.data as DocumentWithMemories).memoryEntries[0]?.spaceId ?? - "default" - - if (spaceA !== spaceB) return - - const dx = nodeB.x - nodeA.x - const dy = nodeB.y - nodeA.y - const dist = Math.sqrt(dx * dx + dy * dy) || 1 - - if (dist < minDocDist) { - // Much gentler push with dampening - const push = (minDocDist - dist) / 8 - const dampening = Math.max(0.1, Math.min(1, dist / minDocDist)) - const smoothPush = push * dampening * 0.5 - - const nx = dx / dist - const ny = dy / dist - nodeA.x -= nx * smoothPush - nodeA.y -= ny * smoothPush - nodeB.x += nx * smoothPush - nodeB.y += ny * smoothPush - } - }) - }) - } + /* 2. Manual collision avoidance removed - now handled by d3-force simulation */ + // The initial circular layout provides good starting positions + // D3-force will handle collision avoidance and spacing dynamically allNodes.push(...documentNodes) - + /* 3. Add memories around documents WITH doc-memory connections */ documentNodes.forEach((docNode) => { const memoryNodeMap = new Map<string, GraphNode>() @@ -185,34 +304,58 @@ export function useGraphData( const memoryId = `${memory.id}` const customMemPos = nodePositions.get(memoryId) - const clusterAngle = (memIndex / doc.memoryEntries.length) * Math.PI * 2 - const variation = Math.sin(memIndex * 2.5) * 0.3 + 0.7 - const distance = clusterRadius * variation - - const seed = - memIndex * 12345 + Number.parseInt(docNode.id.slice(0, 6), 36) - const offsetX = Math.sin(seed) * 0.5 * 40 - const offsetY = Math.cos(seed) * 0.5 * 40 - - const defaultMemX = - docNode.x + Math.cos(clusterAngle) * distance + offsetX - const defaultMemY = - docNode.y + Math.sin(clusterAngle) * distance + offsetY + // Simple circular positioning around parent doc + // Physics will naturally cluster them better + const angle = (memIndex / doc.memoryEntries.length) * Math.PI * 2 + const distance = clusterRadius * 1 // Closer to parent, let physics separate + + const defaultMemX = docNode.x + Math.cos(angle) * distance + const defaultMemY = docNode.y + Math.sin(angle) * distance + + // Calculate final position + let finalMemX = defaultMemX + let finalMemY = defaultMemY + + if (customMemPos) { + // If memory was manually positioned and has stored offset relative to parent + if (customMemPos.parentDocId === docNode.id && + customMemPos.offsetX !== undefined && + customMemPos.offsetY !== undefined) { + // Apply the stored offset to the current document position + finalMemX = docNode.x + customMemPos.offsetX + finalMemY = docNode.y + customMemPos.offsetY + } else { + // Fallback: use absolute position (for backward compatibility or if parent changed) + finalMemX = customMemPos.x + finalMemY = customMemPos.y + } + } if (!memoryNodeMap.has(memoryId)) { - const memoryNode: GraphNode = { - id: memoryId, - type: "memory", - x: customMemPos?.x ?? defaultMemX, - y: customMemPos?.y ?? defaultMemY, - data: memory, - size: Math.max( - 32, - Math.min(48, (memory.memory?.length || 50) * 0.5), - ), - color: colors.memory.primary, - isHovered: false, - isDragging: draggingNodeId === memoryId, + // Check if memory node exists in cache (preserves d3-force mutations) + let memoryNode = nodeCache.current.get(memoryId) + if (memoryNode) { + // Update existing node's data, preserve physics properties + memoryNode.data = memory + memoryNode.isDragging = draggingNodeId === memoryId + // Don't reset x/y - they're managed by d3-force + } else { + // Create new node with initial position + memoryNode = { + id: memoryId, + type: "memory", + x: finalMemX, + y: finalMemY, + data: memory, + size: Math.max( + 32, + Math.min(48, (memory.memory?.length || 50) * 0.5), + ), + color: colors.memory.primary, + isHovered: false, + isDragging: draggingNodeId === memoryId, + } + nodeCache.current.set(memoryId, memoryNode) } memoryNodeMap.set(memoryId, memoryNode) allNodes.push(memoryNode) @@ -243,7 +386,7 @@ export function useGraphData( data.documents.forEach((doc) => { doc.memoryEntries.forEach((mem: MemoryEntry) => { // Support both new object structure and legacy array/single parent fields - let parentRelations: Record<string, MemoryRelation> = {} + let parentRelations: Record<string, MemoryRelation> = (mem.memoryRelations ?? {}) as Record<string, MemoryRelation> if ( mem.memoryRelations && @@ -288,33 +431,9 @@ export function useGraphData( }) }) - // Document-to-document similarity edges - for (let i = 0; i < filteredDocuments.length; i++) { - const docI = filteredDocuments[i] - if (!docI) continue - - for (let j = i + 1; j < filteredDocuments.length; j++) { - const docJ = filteredDocuments[j] - if (!docJ) continue - - const sim = calculateSemanticSimilarity( - docI.summaryEmbedding ? Array.from(docI.summaryEmbedding) : null, - docJ.summaryEmbedding ? Array.from(docJ.summaryEmbedding) : null, - ) - if (sim > 0.725) { - allEdges.push({ - id: `doc-doc-${docI.id}-${docJ.id}`, - source: docI.id, - target: docJ.id, - similarity: sim, - visualProps: getConnectionVisualProps(sim), - color: getMagicalConnectionColor(sim, 200), - edgeType: "doc-doc", - }) - } - } - } + // Append similarity edges (calculated in separate memo) + allEdges.push(...similarityEdges) return { nodes: allNodes, edges: allEdges } - }, [data, selectedSpace, nodePositions, draggingNodeId, memoryLimit]) -} + }, [data, filteredDocuments, nodePositions, draggingNodeId, similarityEdges]) +}
\ No newline at end of file diff --git a/packages/memory-graph/src/hooks/use-graph-interactions.ts b/packages/memory-graph/src/hooks/use-graph-interactions.ts index 94fc88ee..bcf0f5dd 100644 --- a/packages/memory-graph/src/hooks/use-graph-interactions.ts +++ b/packages/memory-graph/src/hooks/use-graph-interactions.ts @@ -24,7 +24,7 @@ export function useGraphInteractions( nodeY: 0, }) const [nodePositions, setNodePositions] = useState< - Map<string, { x: number; y: number }> + Map<string, { x: number; y: number; parentDocId?: string; offsetX?: number; offsetY?: number }> >(new Map()) // Touch gesture state @@ -109,7 +109,7 @@ export function useGraphInteractions( ) const handleNodeDragMove = useCallback( - (e: React.MouseEvent) => { + (e: React.MouseEvent, nodes?: GraphNode[]) => { if (!draggingNodeId) return const deltaX = (e.clientX - dragStart.x) / zoom @@ -118,6 +118,36 @@ export function useGraphInteractions( const newX = dragStart.nodeX + deltaX const newY = dragStart.nodeY + deltaY + // Find the node being dragged to determine if it's a memory + const draggedNode = nodes?.find((n) => n.id === draggingNodeId) + + if (draggedNode?.type === "memory") { + // For memory nodes, find the parent document and store relative offset + const memoryData = draggedNode.data as any // MemoryEntry type + const parentDoc = nodes?.find( + (n) => n.type === "document" && + (n.data as any).memoryEntries?.some((m: any) => m.id === memoryData.id) + ) + + if (parentDoc) { + // Store the offset from the parent document + const offsetX = newX - parentDoc.x + const offsetY = newY - parentDoc.y + + setNodePositions((prev) => + new Map(prev).set(draggingNodeId, { + x: newX, + y: newY, + parentDocId: parentDoc.id, + offsetX, + offsetY + }), + ) + return + } + } + + // For document nodes or if parent not found, just store absolute position setNodePositions((prev) => new Map(prev).set(draggingNodeId, { x: newX, y: newY }), ) diff --git a/packages/memory-graph/src/types.ts b/packages/memory-graph/src/types.ts index 73d0602a..f470223b 100644 --- a/packages/memory-graph/src/types.ts +++ b/packages/memory-graph/src/types.ts @@ -17,14 +17,20 @@ export interface GraphNode { color: string isHovered: boolean isDragging: boolean + // D3-force simulation properties + vx?: number // velocity x + vy?: number // velocity y + fx?: number | null // fixed x position (for pinning during drag) + fy?: number | null // fixed y position (for pinning during drag) } export type MemoryRelation = "updates" | "extends" | "derives" export interface GraphEdge { id: string - source: string - target: string + // D3-force mutates source/target from string IDs to node references during simulation + source: string | GraphNode + target: string | GraphNode similarity: number visualProps: { opacity: number @@ -74,6 +80,10 @@ export interface GraphCanvasProps { draggingNodeId: string | null // Optional list of document IDs (customId or internal id) to highlight highlightDocumentIds?: string[] + // Physics simulation state + isSimulationActive?: boolean + // Selected node ID - dims all other nodes and edges + selectedNodeId?: string | null } export interface MemoryGraphProps { @@ -119,10 +129,20 @@ export interface MemoryGraphProps { // Memory limit control /** Maximum number of memories to display per document when a space is selected */ memoryLimit?: number + /** Maximum total number of memory nodes to display across all documents (default: unlimited) */ + maxNodes?: number // Feature flags /** Enable experimental features */ isExperimental?: boolean + + // Slideshow control + /** Whether slideshow mode is currently active */ + isSlideshowActive?: boolean + /** Callback when slideshow selects a new node (provides node ID) */ + onSlideshowNodeChange?: (nodeId: string | null) => void + /** Callback when user clicks outside during slideshow (to stop it) */ + onSlideshowStop?: () => void } export interface LegendProps { diff --git a/packages/memory-graph/src/utils/document-icons.ts b/packages/memory-graph/src/utils/document-icons.ts new file mode 100644 index 00000000..2e93c22a --- /dev/null +++ b/packages/memory-graph/src/utils/document-icons.ts @@ -0,0 +1,237 @@ +/** + * Canvas-based document type icon rendering utilities + * Simplified to match supported file types: PDF, TXT, MD, DOCX, DOC, RTF, CSV, JSON + */ + +export type DocumentIconType = + | "text" + | "pdf" + | "md" + | "markdown" + | "docx" + | "doc" + | "rtf" + | "csv" + | "json" + +/** + * Draws a document type icon on canvas + * @param ctx - Canvas 2D rendering context + * @param x - X position (center of icon) + * @param y - Y position (center of icon) + * @param size - Icon size (width/height) + * @param type - Document type + * @param color - Icon color (default: white) + */ +export function drawDocumentIcon( + ctx: CanvasRenderingContext2D, + x: number, + y: number, + size: number, + type: string, + color = "rgba(255, 255, 255, 0.9)", +): void { + ctx.save() + ctx.fillStyle = color + ctx.strokeStyle = color + ctx.lineWidth = Math.max(1, size / 12) + ctx.lineCap = "round" + ctx.lineJoin = "round" + + switch (type) { + case "pdf": + drawPdfIcon(ctx, x, y, size) + break + case "md": + case "markdown": + drawMarkdownIcon(ctx, x, y, size) + break + case "doc": + case "docx": + drawWordIcon(ctx, x, y, size) + break + case "rtf": + drawRtfIcon(ctx, x, y, size) + break + case "csv": + drawCsvIcon(ctx, x, y, size) + break + case "json": + drawJsonIcon(ctx, x, y, size) + break + case "txt": + case "text": + default: + drawTextIcon(ctx, x, y, size) + break + } + + ctx.restore() +} + +// Individual icon drawing functions + +function drawTextIcon( + ctx: CanvasRenderingContext2D, + x: number, + y: number, + size: number, +): void { + // Simple document outline with lines + const w = size * 0.7 + const h = size * 0.85 + const cornerFold = size * 0.2 + + ctx.beginPath() + ctx.moveTo(x - w / 2, y - h / 2) + ctx.lineTo(x + w / 2 - cornerFold, y - h / 2) + ctx.lineTo(x + w / 2, y - h / 2 + cornerFold) + ctx.lineTo(x + w / 2, y + h / 2) + ctx.lineTo(x - w / 2, y + h / 2) + ctx.closePath() + ctx.stroke() + + // Text lines + const lineSpacing = size * 0.15 + const lineWidth = size * 0.4 + ctx.beginPath() + ctx.moveTo(x - lineWidth / 2, y - lineSpacing) + ctx.lineTo(x + lineWidth / 2, y - lineSpacing) + ctx.moveTo(x - lineWidth / 2, y) + ctx.lineTo(x + lineWidth / 2, y) + ctx.moveTo(x - lineWidth / 2, y + lineSpacing) + ctx.lineTo(x + lineWidth / 2, y + lineSpacing) + ctx.stroke() +} + +function drawPdfIcon( + ctx: CanvasRenderingContext2D, + x: number, + y: number, + size: number, +): void { + // Document with "PDF" text + const w = size * 0.7 + const h = size * 0.85 + + ctx.beginPath() + ctx.rect(x - w / 2, y - h / 2, w, h) + ctx.stroke() + + // "PDF" letters (simplified) + ctx.font = `bold ${size * 0.35}px sans-serif` + ctx.textAlign = "center" + ctx.textBaseline = "middle" + ctx.fillText("PDF", x, y) +} + +function drawMarkdownIcon( + ctx: CanvasRenderingContext2D, + x: number, + y: number, + size: number, +): void { + // Document with "MD" text + const w = size * 0.7 + const h = size * 0.85 + + ctx.beginPath() + ctx.rect(x - w / 2, y - h / 2, w, h) + ctx.stroke() + + // "MD" letters + ctx.font = `bold ${size * 0.3}px sans-serif` + ctx.textAlign = "center" + ctx.textBaseline = "middle" + ctx.fillText("MD", x, y) +} + +function drawWordIcon( + ctx: CanvasRenderingContext2D, + x: number, + y: number, + size: number, +): void { + // Document with "DOC" text + const w = size * 0.7 + const h = size * 0.85 + + ctx.beginPath() + ctx.rect(x - w / 2, y - h / 2, w, h) + ctx.stroke() + + // "DOC" letters + ctx.font = `bold ${size * 0.28}px sans-serif` + ctx.textAlign = "center" + ctx.textBaseline = "middle" + ctx.fillText("DOC", x, y) +} + +function drawRtfIcon( + ctx: CanvasRenderingContext2D, + x: number, + y: number, + size: number, +): void { + // Document with "RTF" text + const w = size * 0.7 + const h = size * 0.85 + + ctx.beginPath() + ctx.rect(x - w / 2, y - h / 2, w, h) + ctx.stroke() + + // "RTF" letters + ctx.font = `bold ${size * 0.3}px sans-serif` + ctx.textAlign = "center" + ctx.textBaseline = "middle" + ctx.fillText("RTF", x, y) +} + +function drawCsvIcon( + ctx: CanvasRenderingContext2D, + x: number, + y: number, + size: number, +): void { + // Grid table for CSV + const w = size * 0.7 + const h = size * 0.85 + + ctx.strokeRect(x - w / 2, y - h / 2, w, h) + + // Grid lines (2x2) + ctx.beginPath() + // Vertical line + ctx.moveTo(x, y - h / 2) + ctx.lineTo(x, y + h / 2) + // Horizontal line + ctx.moveTo(x - w / 2, y) + ctx.lineTo(x + w / 2, y) + ctx.stroke() +} + +function drawJsonIcon( + ctx: CanvasRenderingContext2D, + x: number, + y: number, + size: number, +): void { + // Curly braces for JSON + const w = size * 0.6 + const h = size * 0.8 + + // Left brace + ctx.beginPath() + ctx.moveTo(x - w / 4, y - h / 2) + ctx.quadraticCurveTo(x - w / 2, y - h / 3, x - w / 2, y) + ctx.quadraticCurveTo(x - w / 2, y + h / 3, x - w / 4, y + h / 2) + ctx.stroke() + + // Right brace + ctx.beginPath() + ctx.moveTo(x + w / 4, y - h / 2) + ctx.quadraticCurveTo(x + w / 2, y - h / 3, x + w / 2, y) + ctx.quadraticCurveTo(x + w / 2, y + h / 3, x + w / 4, y + h / 2) + ctx.stroke() +} |