diff --git a/Cargo.lock b/Cargo.lock index c0bda7edbfeb1a..0c654e633b1e06 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -610,7 +610,7 @@ dependencies = [ "bitflags 2.9.1", "cexpr", "clang-sys", - "itertools 0.10.5", + "itertools 0.12.1", "lazy_static", "lazycell", "log", @@ -4641,7 +4641,7 @@ version = "0.50.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7957b9740744892f114936ab4a57b3f487491bbeafaf8083688b16841a4240e5" dependencies = [ - "windows-sys 0.60.2", + "windows-sys 0.61.2", ] [[package]] @@ -5641,7 +5641,7 @@ dependencies = [ "once_cell", "socket2 0.5.10", "tracing", - "windows-sys 0.52.0", + "windows-sys 0.60.2", ] [[package]] @@ -6247,7 +6247,7 @@ dependencies = [ "security-framework 3.5.1", "security-framework-sys", "webpki-root-certs", - "windows-sys 0.52.0", + "windows-sys 0.61.2", ] [[package]] @@ -9513,6 +9513,7 @@ dependencies = [ "turbo-tasks-fs", "turbo-tasks-testing", "turbopack-core", + "webpki-root-certs", ] [[package]] @@ -9535,6 +9536,7 @@ dependencies = [ "mime", "notify", "parking_lot", + "rand 0.9.0", "regex", "rstest", "rustc-hash 2.1.1", @@ -9543,6 +9545,7 @@ dependencies = [ "serde_path_to_error", "sha2", "tempfile", + "thiserror 1.0.69", "tokio", "tracing", "triomphe 0.1.12", diff --git a/lerna.json b/lerna.json index adfaabf5c5aa7a..f1e00319f56287 100644 --- a/lerna.json +++ b/lerna.json @@ -15,5 +15,5 @@ "registry": "https://registry.npmjs.org/" } }, - "version": "16.2.0-canary.0" + "version": "16.2.0-canary.1" } \ No newline at end of file diff --git a/package.json b/package.json index d57ca232d9b530..4e2268bd1cd18b 100644 --- a/package.json +++ b/package.json @@ -198,7 +198,7 @@ "eslint-plugin-jsdoc": "48.0.4", "eslint-plugin-mdx": "3.1.5", "eslint-plugin-react": "7.37.0", - "eslint-plugin-react-hooks": "0.0.0-experimental-d2908752-20260119", + "eslint-plugin-react-hooks": "0.0.0-experimental-b546603b-20260121", "event-stream": "4.0.1", "execa": "2.0.3", "expect": "29.7.0", @@ -258,16 +258,16 @@ "pretty-ms": "7.0.0", "random-seed": "0.3.0", "react": "19.0.0", - "react-builtin": "npm:react@19.3.0-canary-d2908752-20260119", + "react-builtin": "npm:react@19.3.0-canary-b546603b-20260121", "react-dom": "19.0.0", - "react-dom-builtin": "npm:react-dom@19.3.0-canary-d2908752-20260119", - "react-dom-experimental-builtin": "npm:react-dom@0.0.0-experimental-d2908752-20260119", - "react-experimental-builtin": "npm:react@0.0.0-experimental-d2908752-20260119", - "react-is-builtin": "npm:react-is@19.3.0-canary-d2908752-20260119", - "react-server-dom-turbopack": "19.3.0-canary-d2908752-20260119", - "react-server-dom-turbopack-experimental": "npm:react-server-dom-turbopack@0.0.0-experimental-d2908752-20260119", - "react-server-dom-webpack": "19.3.0-canary-d2908752-20260119", - "react-server-dom-webpack-experimental": "npm:react-server-dom-webpack@0.0.0-experimental-d2908752-20260119", + "react-dom-builtin": "npm:react-dom@19.3.0-canary-b546603b-20260121", + "react-dom-experimental-builtin": "npm:react-dom@0.0.0-experimental-b546603b-20260121", + "react-experimental-builtin": "npm:react@0.0.0-experimental-b546603b-20260121", + "react-is-builtin": "npm:react-is@19.3.0-canary-b546603b-20260121", + "react-server-dom-turbopack": "19.3.0-canary-b546603b-20260121", + "react-server-dom-turbopack-experimental": "npm:react-server-dom-turbopack@0.0.0-experimental-b546603b-20260121", + "react-server-dom-webpack": "19.3.0-canary-b546603b-20260121", + "react-server-dom-webpack-experimental": "npm:react-server-dom-webpack@0.0.0-experimental-b546603b-20260121", "react-ssr-prepass": "1.0.8", "react-virtualized": "9.22.3", "relay-compiler": "13.0.2", @@ -277,8 +277,8 @@ "resolve-from": "5.0.0", "sass": "1.54.0", "satori": "0.15.2", - "scheduler-builtin": "npm:scheduler@0.28.0-canary-d2908752-20260119", - "scheduler-experimental-builtin": "npm:scheduler@0.0.0-experimental-d2908752-20260119", + "scheduler-builtin": "npm:scheduler@0.28.0-canary-b546603b-20260121", + "scheduler-experimental-builtin": "npm:scheduler@0.0.0-experimental-b546603b-20260121", "seedrandom": "3.0.5", "semver": "7.3.7", "serve-handler": "6.1.6", @@ -323,10 +323,10 @@ "@types/react-dom": "19.2.1", "@types/retry": "0.12.0", "jest-snapshot": "30.0.0-alpha.6", - "react": "19.3.0-canary-d2908752-20260119", - "react-dom": "19.3.0-canary-d2908752-20260119", - "react-is": "19.3.0-canary-d2908752-20260119", - "scheduler": "0.28.0-canary-d2908752-20260119" + "react": "19.3.0-canary-b546603b-20260121", + "react-dom": "19.3.0-canary-b546603b-20260121", + "react-is": "19.3.0-canary-b546603b-20260121", + "scheduler": "0.28.0-canary-b546603b-20260121" }, "packageExtensions": { "eslint-plugin-react-hooks@0.0.0-experimental-6de32a5a-20250822": { diff --git a/packages/create-next-app/package.json b/packages/create-next-app/package.json index 0f066f884d61f7..4f668a2aae671e 100644 --- a/packages/create-next-app/package.json +++ b/packages/create-next-app/package.json @@ -1,6 +1,6 @@ { "name": "create-next-app", - "version": "16.2.0-canary.0", + "version": "16.2.0-canary.1", "keywords": [ "react", "next", diff --git a/packages/eslint-config-next/package.json b/packages/eslint-config-next/package.json index 8e19ce1410f00c..5d4b63db62d927 100644 --- a/packages/eslint-config-next/package.json +++ b/packages/eslint-config-next/package.json @@ -1,6 +1,6 @@ { "name": "eslint-config-next", - "version": "16.2.0-canary.0", + "version": "16.2.0-canary.1", "description": "ESLint configuration used by Next.js.", "license": "MIT", "repository": { @@ -12,7 +12,7 @@ "dist" ], "dependencies": { - "@next/eslint-plugin-next": "16.2.0-canary.0", + "@next/eslint-plugin-next": "16.2.0-canary.1", "eslint-import-resolver-node": "^0.3.6", "eslint-import-resolver-typescript": "^3.5.2", "eslint-plugin-import": "^2.32.0", diff --git a/packages/eslint-plugin-internal/package.json b/packages/eslint-plugin-internal/package.json index f3338a11c6fee9..17e19fc56e4db8 100644 --- a/packages/eslint-plugin-internal/package.json +++ b/packages/eslint-plugin-internal/package.json @@ -1,7 +1,7 @@ { "name": "@next/eslint-plugin-internal", "private": true, - "version": "16.2.0-canary.0", + "version": "16.2.0-canary.1", "description": "ESLint plugin for working on Next.js.", "exports": { ".": "./src/eslint-plugin-internal.js" diff --git a/packages/eslint-plugin-next/package.json b/packages/eslint-plugin-next/package.json index 71d390ade77004..350dfafa0dc852 100644 --- a/packages/eslint-plugin-next/package.json +++ b/packages/eslint-plugin-next/package.json @@ -1,6 +1,6 @@ { "name": "@next/eslint-plugin-next", - "version": "16.2.0-canary.0", + "version": "16.2.0-canary.1", "description": "ESLint plugin for Next.js.", "main": "dist/index.js", "types": "dist/index.d.ts", diff --git a/packages/font/package.json b/packages/font/package.json index e5b85400f50d2d..710f10a7033c14 100644 --- a/packages/font/package.json +++ b/packages/font/package.json @@ -1,7 +1,7 @@ { "name": "@next/font", "private": true, - "version": "16.2.0-canary.0", + "version": "16.2.0-canary.1", "repository": { "url": "vercel/next.js", "directory": "packages/font" diff --git a/packages/next-bundle-analyzer/package.json b/packages/next-bundle-analyzer/package.json index b5b8e4fc69473c..b658f2a910dcf8 100644 --- a/packages/next-bundle-analyzer/package.json +++ b/packages/next-bundle-analyzer/package.json @@ -1,6 +1,6 @@ { "name": "@next/bundle-analyzer", - "version": "16.2.0-canary.0", + "version": "16.2.0-canary.1", "main": "index.js", "types": "index.d.ts", "license": "MIT", diff --git a/packages/next-codemod/package.json b/packages/next-codemod/package.json index 591c54d6165946..b5e0b4fa30f09f 100644 --- a/packages/next-codemod/package.json +++ b/packages/next-codemod/package.json @@ -1,6 +1,6 @@ { "name": "@next/codemod", - "version": "16.2.0-canary.0", + "version": "16.2.0-canary.1", "license": "MIT", "repository": { "type": "git", diff --git a/packages/next-env/package.json b/packages/next-env/package.json index 6c6b8587aa3ed4..3a498595b5fe58 100644 --- a/packages/next-env/package.json +++ b/packages/next-env/package.json @@ -1,6 +1,6 @@ { "name": "@next/env", - "version": "16.2.0-canary.0", + "version": "16.2.0-canary.1", "keywords": [ "react", "next", diff --git a/packages/next-mdx/package.json b/packages/next-mdx/package.json index 9420496a96e4b9..71ed3b74004645 100644 --- a/packages/next-mdx/package.json +++ b/packages/next-mdx/package.json @@ -1,6 +1,6 @@ { "name": "@next/mdx", - "version": "16.2.0-canary.0", + "version": "16.2.0-canary.1", "main": "index.js", "license": "MIT", "repository": { diff --git a/packages/next-plugin-storybook/package.json b/packages/next-plugin-storybook/package.json index 1e3bfa431f2300..b8e52416948cb0 100644 --- a/packages/next-plugin-storybook/package.json +++ b/packages/next-plugin-storybook/package.json @@ -1,6 +1,6 @@ { "name": "@next/plugin-storybook", - "version": "16.2.0-canary.0", + "version": "16.2.0-canary.1", "repository": { "url": "vercel/next.js", "directory": "packages/next-plugin-storybook" diff --git a/packages/next-polyfill-module/package.json b/packages/next-polyfill-module/package.json index 5615447bc28ef4..220e1af3cef9b3 100644 --- a/packages/next-polyfill-module/package.json +++ b/packages/next-polyfill-module/package.json @@ -1,6 +1,6 @@ { "name": "@next/polyfill-module", - "version": "16.2.0-canary.0", + "version": "16.2.0-canary.1", "description": "A standard library polyfill for ES Modules supporting browsers (Edge 16+, Firefox 60+, Chrome 61+, Safari 10.1+)", "main": "dist/polyfill-module.js", "license": "MIT", diff --git a/packages/next-polyfill-nomodule/package.json b/packages/next-polyfill-nomodule/package.json index b1f24f56b0c214..bf447d6950b983 100644 --- a/packages/next-polyfill-nomodule/package.json +++ b/packages/next-polyfill-nomodule/package.json @@ -1,6 +1,6 @@ { "name": "@next/polyfill-nomodule", - "version": "16.2.0-canary.0", + "version": "16.2.0-canary.1", "description": "A polyfill for non-dead, nomodule browsers.", "main": "dist/polyfill-nomodule.js", "license": "MIT", diff --git a/packages/next-routing/package.json b/packages/next-routing/package.json index 41be69a7d81061..05dfdb1cdd9a88 100644 --- a/packages/next-routing/package.json +++ b/packages/next-routing/package.json @@ -1,6 +1,6 @@ { "name": "@next/routing", - "version": "16.2.0-canary.0", + "version": "16.2.0-canary.1", "keywords": [ "react", "next", diff --git a/packages/next-rspack/package.json b/packages/next-rspack/package.json index 6ae330bb999e48..17b79a5ad04c23 100644 --- a/packages/next-rspack/package.json +++ b/packages/next-rspack/package.json @@ -1,6 +1,6 @@ { "name": "next-rspack", - "version": "16.2.0-canary.0", + "version": "16.2.0-canary.1", "repository": { "url": "vercel/next.js", "directory": "packages/next-rspack" diff --git a/packages/next-swc/package.json b/packages/next-swc/package.json index ada17bc13c5be2..32a6e9df9365e1 100644 --- a/packages/next-swc/package.json +++ b/packages/next-swc/package.json @@ -1,6 +1,6 @@ { "name": "@next/swc", - "version": "16.2.0-canary.0", + "version": "16.2.0-canary.1", "private": true, "files": [ "native/" diff --git a/packages/next/package.json b/packages/next/package.json index bfd5572d8bd2e1..a714fdbb4e1c74 100644 --- a/packages/next/package.json +++ b/packages/next/package.json @@ -1,6 +1,6 @@ { "name": "next", - "version": "16.2.0-canary.0", + "version": "16.2.0-canary.1", "description": "The React Framework", "main": "./dist/server/next.js", "license": "MIT", @@ -97,7 +97,7 @@ ] }, "dependencies": { - "@next/env": "16.2.0-canary.0", + "@next/env": "16.2.0-canary.1", "@swc/helpers": "0.5.15", "baseline-browser-mapping": "^2.8.3", "caniuse-lite": "^1.0.30001579", @@ -162,11 +162,11 @@ "@modelcontextprotocol/sdk": "1.18.1", "@mswjs/interceptors": "0.23.0", "@napi-rs/triples": "1.2.0", - "@next/font": "16.2.0-canary.0", - "@next/polyfill-module": "16.2.0-canary.0", - "@next/polyfill-nomodule": "16.2.0-canary.0", - "@next/react-refresh-utils": "16.2.0-canary.0", - "@next/swc": "16.2.0-canary.0", + "@next/font": "16.2.0-canary.1", + "@next/polyfill-module": "16.2.0-canary.1", + "@next/polyfill-nomodule": "16.2.0-canary.1", + "@next/react-refresh-utils": "16.2.0-canary.1", + "@next/swc": "16.2.0-canary.1", "@opentelemetry/api": "1.6.0", "@playwright/test": "1.51.1", "@rspack/core": "1.6.7", diff --git a/packages/next/src/compiled/react-dom-experimental/cjs/react-dom-client.development.js b/packages/next/src/compiled/react-dom-experimental/cjs/react-dom-client.development.js index ce13015f483ebe..8eed3f9708efd3 100644 --- a/packages/next/src/compiled/react-dom-experimental/cjs/react-dom-client.development.js +++ b/packages/next/src/compiled/react-dom-experimental/cjs/react-dom-client.development.js @@ -123,18 +123,12 @@ ); } function getNearestMountedFiber(fiber) { - var node = fiber, - nearestMounted = fiber; - if (fiber.alternate) for (; node.return; ) node = node.return; - else { - fiber = node; - do - (node = fiber), - 0 !== (node.flags & 4098) && (nearestMounted = node.return), - (fiber = node.return); - while (fiber); - } - return 3 === node.tag ? nearestMounted : null; + for (var node = fiber, nextNode = node; nextNode && !nextNode.alternate; ) + (node = nextNode), + 0 !== (node.flags & 4098) && (fiber = node.return), + (nextNode = node.return); + for (; node.return; ) node = node.return; + return 3 === node.tag ? fiber : null; } function getSuspenseInstanceFromFiber(fiber) { if (13 === fiber.tag) { @@ -32678,11 +32672,11 @@ }; (function () { var isomorphicReactPackageVersion = React.version; - if ("19.3.0-experimental-d2908752-20260119" !== isomorphicReactPackageVersion) + if ("19.3.0-experimental-b546603b-20260121" !== isomorphicReactPackageVersion) throw Error( 'Incompatible React versions: The "react" and "react-dom" packages must have the exact same version. Instead got:\n - react: ' + (isomorphicReactPackageVersion + - "\n - react-dom: 19.3.0-experimental-d2908752-20260119\nLearn more: https://react.dev/warnings/version-mismatch") + "\n - react-dom: 19.3.0-experimental-b546603b-20260121\nLearn more: https://react.dev/warnings/version-mismatch") ); })(); ("function" === typeof Map && @@ -32719,10 +32713,10 @@ !(function () { var internals = { bundleType: 1, - version: "19.3.0-experimental-d2908752-20260119", + version: "19.3.0-experimental-b546603b-20260121", rendererPackageName: "react-dom", currentDispatcherRef: ReactSharedInternals, - reconcilerVersion: "19.3.0-experimental-d2908752-20260119" + reconcilerVersion: "19.3.0-experimental-b546603b-20260121" }; internals.overrideHookState = overrideHookState; internals.overrideHookStateDeletePath = overrideHookStateDeletePath; @@ -32870,7 +32864,7 @@ listenToAllSupportedEvents(container); return new ReactDOMHydrationRoot(initialChildren); }; - exports.version = "19.3.0-experimental-d2908752-20260119"; + exports.version = "19.3.0-experimental-b546603b-20260121"; "undefined" !== typeof __REACT_DEVTOOLS_GLOBAL_HOOK__ && "function" === typeof __REACT_DEVTOOLS_GLOBAL_HOOK__.registerInternalModuleStop && diff --git a/packages/next/src/compiled/react-dom-experimental/cjs/react-dom-client.production.js b/packages/next/src/compiled/react-dom-experimental/cjs/react-dom-client.production.js index d66c1cfea2a919..3898c00e269260 100644 --- a/packages/next/src/compiled/react-dom-experimental/cjs/react-dom-client.production.js +++ b/packages/next/src/compiled/react-dom-experimental/cjs/react-dom-client.production.js @@ -37,18 +37,12 @@ function isValidContainer(node) { ); } function getNearestMountedFiber(fiber) { - var node = fiber, - nearestMounted = fiber; - if (fiber.alternate) for (; node.return; ) node = node.return; - else { - fiber = node; - do - (node = fiber), - 0 !== (node.flags & 4098) && (nearestMounted = node.return), - (fiber = node.return); - while (fiber); - } - return 3 === node.tag ? nearestMounted : null; + for (var node = fiber, nextNode = node; nextNode && !nextNode.alternate; ) + (node = nextNode), + 0 !== (node.flags & 4098) && (fiber = node.return), + (nextNode = node.return); + for (; node.return; ) node = node.return; + return 3 === node.tag ? fiber : null; } function getSuspenseInstanceFromFiber(fiber) { if (13 === fiber.tag) { @@ -19831,14 +19825,14 @@ ReactDOMHydrationRoot.prototype.unstable_scheduleHydration = function (target) { }; var isomorphicReactPackageVersion$jscomp$inline_2237 = React.version; if ( - "19.3.0-experimental-d2908752-20260119" !== + "19.3.0-experimental-b546603b-20260121" !== isomorphicReactPackageVersion$jscomp$inline_2237 ) throw Error( formatProdErrorMessage( 527, isomorphicReactPackageVersion$jscomp$inline_2237, - "19.3.0-experimental-d2908752-20260119" + "19.3.0-experimental-b546603b-20260121" ) ); ReactDOMSharedInternals.findDOMNode = function (componentOrElement) { @@ -19860,10 +19854,10 @@ ReactDOMSharedInternals.findDOMNode = function (componentOrElement) { }; var internals$jscomp$inline_2940 = { bundleType: 0, - version: "19.3.0-experimental-d2908752-20260119", + version: "19.3.0-experimental-b546603b-20260121", rendererPackageName: "react-dom", currentDispatcherRef: ReactSharedInternals, - reconcilerVersion: "19.3.0-experimental-d2908752-20260119" + reconcilerVersion: "19.3.0-experimental-b546603b-20260121" }; if ("undefined" !== typeof __REACT_DEVTOOLS_GLOBAL_HOOK__) { var hook$jscomp$inline_2941 = __REACT_DEVTOOLS_GLOBAL_HOOK__; @@ -19970,4 +19964,4 @@ exports.hydrateRoot = function (container, initialChildren, options) { listenToAllSupportedEvents(container); return new ReactDOMHydrationRoot(initialChildren); }; -exports.version = "19.3.0-experimental-d2908752-20260119"; +exports.version = "19.3.0-experimental-b546603b-20260121"; diff --git a/packages/next/src/compiled/react-dom-experimental/cjs/react-dom-profiling.development.js b/packages/next/src/compiled/react-dom-experimental/cjs/react-dom-profiling.development.js index 0c95df5619e004..62c934a4b09b5c 100644 --- a/packages/next/src/compiled/react-dom-experimental/cjs/react-dom-profiling.development.js +++ b/packages/next/src/compiled/react-dom-experimental/cjs/react-dom-profiling.development.js @@ -123,18 +123,12 @@ ); } function getNearestMountedFiber(fiber) { - var node = fiber, - nearestMounted = fiber; - if (fiber.alternate) for (; node.return; ) node = node.return; - else { - fiber = node; - do - (node = fiber), - 0 !== (node.flags & 4098) && (nearestMounted = node.return), - (fiber = node.return); - while (fiber); - } - return 3 === node.tag ? nearestMounted : null; + for (var node = fiber, nextNode = node; nextNode && !nextNode.alternate; ) + (node = nextNode), + 0 !== (node.flags & 4098) && (fiber = node.return), + (nextNode = node.return); + for (; node.return; ) node = node.return; + return 3 === node.tag ? fiber : null; } function getSuspenseInstanceFromFiber(fiber) { if (13 === fiber.tag) { @@ -32735,11 +32729,11 @@ }; (function () { var isomorphicReactPackageVersion = React.version; - if ("19.3.0-experimental-d2908752-20260119" !== isomorphicReactPackageVersion) + if ("19.3.0-experimental-b546603b-20260121" !== isomorphicReactPackageVersion) throw Error( 'Incompatible React versions: The "react" and "react-dom" packages must have the exact same version. Instead got:\n - react: ' + (isomorphicReactPackageVersion + - "\n - react-dom: 19.3.0-experimental-d2908752-20260119\nLearn more: https://react.dev/warnings/version-mismatch") + "\n - react-dom: 19.3.0-experimental-b546603b-20260121\nLearn more: https://react.dev/warnings/version-mismatch") ); })(); ("function" === typeof Map && @@ -32776,10 +32770,10 @@ !(function () { var internals = { bundleType: 1, - version: "19.3.0-experimental-d2908752-20260119", + version: "19.3.0-experimental-b546603b-20260121", rendererPackageName: "react-dom", currentDispatcherRef: ReactSharedInternals, - reconcilerVersion: "19.3.0-experimental-d2908752-20260119" + reconcilerVersion: "19.3.0-experimental-b546603b-20260121" }; internals.overrideHookState = overrideHookState; internals.overrideHookStateDeletePath = overrideHookStateDeletePath; @@ -33257,7 +33251,7 @@ exports.useFormStatus = function () { return resolveDispatcher().useHostTransitionStatus(); }; - exports.version = "19.3.0-experimental-d2908752-20260119"; + exports.version = "19.3.0-experimental-b546603b-20260121"; "undefined" !== typeof __REACT_DEVTOOLS_GLOBAL_HOOK__ && "function" === typeof __REACT_DEVTOOLS_GLOBAL_HOOK__.registerInternalModuleStop && diff --git a/packages/next/src/compiled/react-dom-experimental/cjs/react-dom-profiling.profiling.js b/packages/next/src/compiled/react-dom-experimental/cjs/react-dom-profiling.profiling.js index ae3f29e7f6c8a8..48a96a141d55cd 100644 --- a/packages/next/src/compiled/react-dom-experimental/cjs/react-dom-profiling.profiling.js +++ b/packages/next/src/compiled/react-dom-experimental/cjs/react-dom-profiling.profiling.js @@ -41,18 +41,12 @@ function isValidContainer(node) { ); } function getNearestMountedFiber(fiber) { - var node = fiber, - nearestMounted = fiber; - if (fiber.alternate) for (; node.return; ) node = node.return; - else { - fiber = node; - do - (node = fiber), - 0 !== (node.flags & 4098) && (nearestMounted = node.return), - (fiber = node.return); - while (fiber); - } - return 3 === node.tag ? nearestMounted : null; + for (var node = fiber, nextNode = node; nextNode && !nextNode.alternate; ) + (node = nextNode), + 0 !== (node.flags & 4098) && (fiber = node.return), + (nextNode = node.return); + for (; node.return; ) node = node.return; + return 3 === node.tag ? fiber : null; } function getSuspenseInstanceFromFiber(fiber) { if (13 === fiber.tag) { @@ -21913,14 +21907,14 @@ ReactDOMHydrationRoot.prototype.unstable_scheduleHydration = function (target) { }; var isomorphicReactPackageVersion$jscomp$inline_2541 = React.version; if ( - "19.3.0-experimental-d2908752-20260119" !== + "19.3.0-experimental-b546603b-20260121" !== isomorphicReactPackageVersion$jscomp$inline_2541 ) throw Error( formatProdErrorMessage( 527, isomorphicReactPackageVersion$jscomp$inline_2541, - "19.3.0-experimental-d2908752-20260119" + "19.3.0-experimental-b546603b-20260121" ) ); ReactDOMSharedInternals.findDOMNode = function (componentOrElement) { @@ -21942,10 +21936,10 @@ ReactDOMSharedInternals.findDOMNode = function (componentOrElement) { }; var internals$jscomp$inline_3261 = { bundleType: 0, - version: "19.3.0-experimental-d2908752-20260119", + version: "19.3.0-experimental-b546603b-20260121", rendererPackageName: "react-dom", currentDispatcherRef: ReactSharedInternals, - reconcilerVersion: "19.3.0-experimental-d2908752-20260119" + reconcilerVersion: "19.3.0-experimental-b546603b-20260121" }; if ("undefined" !== typeof __REACT_DEVTOOLS_GLOBAL_HOOK__) { var hook$jscomp$inline_3262 = __REACT_DEVTOOLS_GLOBAL_HOOK__; @@ -22213,7 +22207,7 @@ exports.useFormState = function (action, initialState, permalink) { exports.useFormStatus = function () { return ReactSharedInternals.H.useHostTransitionStatus(); }; -exports.version = "19.3.0-experimental-d2908752-20260119"; +exports.version = "19.3.0-experimental-b546603b-20260121"; "undefined" !== typeof __REACT_DEVTOOLS_GLOBAL_HOOK__ && "function" === typeof __REACT_DEVTOOLS_GLOBAL_HOOK__.registerInternalModuleStop && diff --git a/packages/next/src/compiled/react-dom-experimental/cjs/react-dom-server-legacy.browser.development.js b/packages/next/src/compiled/react-dom-experimental/cjs/react-dom-server-legacy.browser.development.js index 25d993ec5eb1b7..17fdf75ced5517 100644 --- a/packages/next/src/compiled/react-dom-experimental/cjs/react-dom-server-legacy.browser.development.js +++ b/packages/next/src/compiled/react-dom-experimental/cjs/react-dom-server-legacy.browser.development.js @@ -10516,5 +10516,5 @@ 'The server used "renderToString" which does not support Suspense. If you intended for this Suspense boundary to render the fallback content on the server consider throwing an Error somewhere within the Suspense boundary. If you intended to have the server wait for the suspended component please switch to "renderToReadableStream" which supports Suspense on the server' ); }; - exports.version = "19.3.0-experimental-d2908752-20260119"; + exports.version = "19.3.0-experimental-b546603b-20260121"; })(); diff --git a/packages/next/src/compiled/react-dom-experimental/cjs/react-dom-server-legacy.browser.production.js b/packages/next/src/compiled/react-dom-experimental/cjs/react-dom-server-legacy.browser.production.js index 508cb96f67dc27..08396004fc028b 100644 --- a/packages/next/src/compiled/react-dom-experimental/cjs/react-dom-server-legacy.browser.production.js +++ b/packages/next/src/compiled/react-dom-experimental/cjs/react-dom-server-legacy.browser.production.js @@ -7035,4 +7035,4 @@ exports.renderToString = function (children, options) { 'The server used "renderToString" which does not support Suspense. If you intended for this Suspense boundary to render the fallback content on the server consider throwing an Error somewhere within the Suspense boundary. If you intended to have the server wait for the suspended component please switch to "renderToReadableStream" which supports Suspense on the server' ); }; -exports.version = "19.3.0-experimental-d2908752-20260119"; +exports.version = "19.3.0-experimental-b546603b-20260121"; diff --git a/packages/next/src/compiled/react-dom-experimental/cjs/react-dom-server-legacy.node.development.js b/packages/next/src/compiled/react-dom-experimental/cjs/react-dom-server-legacy.node.development.js index 236f7799aa6702..1ad5c837c957fa 100644 --- a/packages/next/src/compiled/react-dom-experimental/cjs/react-dom-server-legacy.node.development.js +++ b/packages/next/src/compiled/react-dom-experimental/cjs/react-dom-server-legacy.node.development.js @@ -10516,5 +10516,5 @@ 'The server used "renderToString" which does not support Suspense. If you intended for this Suspense boundary to render the fallback content on the server consider throwing an Error somewhere within the Suspense boundary. If you intended to have the server wait for the suspended component please switch to "renderToPipeableStream" which supports Suspense on the server' ); }; - exports.version = "19.3.0-experimental-d2908752-20260119"; + exports.version = "19.3.0-experimental-b546603b-20260121"; })(); diff --git a/packages/next/src/compiled/react-dom-experimental/cjs/react-dom-server-legacy.node.production.js b/packages/next/src/compiled/react-dom-experimental/cjs/react-dom-server-legacy.node.production.js index 0f18a73fb0f6f5..5cbd3229fa2c17 100644 --- a/packages/next/src/compiled/react-dom-experimental/cjs/react-dom-server-legacy.node.production.js +++ b/packages/next/src/compiled/react-dom-experimental/cjs/react-dom-server-legacy.node.production.js @@ -7138,4 +7138,4 @@ exports.renderToString = function (children, options) { 'The server used "renderToString" which does not support Suspense. If you intended for this Suspense boundary to render the fallback content on the server consider throwing an Error somewhere within the Suspense boundary. If you intended to have the server wait for the suspended component please switch to "renderToPipeableStream" which supports Suspense on the server' ); }; -exports.version = "19.3.0-experimental-d2908752-20260119"; +exports.version = "19.3.0-experimental-b546603b-20260121"; diff --git a/packages/next/src/compiled/react-dom-experimental/cjs/react-dom-server.browser.development.js b/packages/next/src/compiled/react-dom-experimental/cjs/react-dom-server.browser.development.js index 44c210eb5f6f53..60aae2e4724c87 100644 --- a/packages/next/src/compiled/react-dom-experimental/cjs/react-dom-server.browser.development.js +++ b/packages/next/src/compiled/react-dom-experimental/cjs/react-dom-server.browser.development.js @@ -9492,11 +9492,11 @@ } function ensureCorrectIsomorphicReactVersion() { var isomorphicReactPackageVersion = React.version; - if ("19.3.0-experimental-d2908752-20260119" !== isomorphicReactPackageVersion) + if ("19.3.0-experimental-b546603b-20260121" !== isomorphicReactPackageVersion) throw Error( 'Incompatible React versions: The "react" and "react-dom" packages must have the exact same version. Instead got:\n - react: ' + (isomorphicReactPackageVersion + - "\n - react-dom: 19.3.0-experimental-d2908752-20260119\nLearn more: https://react.dev/warnings/version-mismatch") + "\n - react-dom: 19.3.0-experimental-b546603b-20260121\nLearn more: https://react.dev/warnings/version-mismatch") ); } var React = require("next/dist/compiled/react-experimental"), @@ -11319,5 +11319,5 @@ startWork(request); }); }; - exports.version = "19.3.0-experimental-d2908752-20260119"; + exports.version = "19.3.0-experimental-b546603b-20260121"; })(); diff --git a/packages/next/src/compiled/react-dom-experimental/cjs/react-dom-server.browser.production.js b/packages/next/src/compiled/react-dom-experimental/cjs/react-dom-server.browser.production.js index d51e68ee38545a..43a2793d29ca44 100644 --- a/packages/next/src/compiled/react-dom-experimental/cjs/react-dom-server.browser.production.js +++ b/packages/next/src/compiled/react-dom-experimental/cjs/react-dom-server.browser.production.js @@ -7688,12 +7688,12 @@ function getPostponedState(request) { } function ensureCorrectIsomorphicReactVersion() { var isomorphicReactPackageVersion = React.version; - if ("19.3.0-experimental-d2908752-20260119" !== isomorphicReactPackageVersion) + if ("19.3.0-experimental-b546603b-20260121" !== isomorphicReactPackageVersion) throw Error( formatProdErrorMessage( 527, isomorphicReactPackageVersion, - "19.3.0-experimental-d2908752-20260119" + "19.3.0-experimental-b546603b-20260121" ) ); } @@ -7944,4 +7944,4 @@ exports.resumeAndPrerender = function (children, postponedState, options) { startWork(request); }); }; -exports.version = "19.3.0-experimental-d2908752-20260119"; +exports.version = "19.3.0-experimental-b546603b-20260121"; diff --git a/packages/next/src/compiled/react-dom-experimental/cjs/react-dom-server.bun.production.js b/packages/next/src/compiled/react-dom-experimental/cjs/react-dom-server.bun.production.js index 410e3966756045..1644f0ca4f76c0 100644 --- a/packages/next/src/compiled/react-dom-experimental/cjs/react-dom-server.bun.production.js +++ b/packages/next/src/compiled/react-dom-experimental/cjs/react-dom-server.bun.production.js @@ -7383,11 +7383,11 @@ function getPostponedState(request) { } function ensureCorrectIsomorphicReactVersion() { var isomorphicReactPackageVersion = React.version; - if ("19.3.0-experimental-d2908752-20260119" !== isomorphicReactPackageVersion) + if ("19.3.0-experimental-b546603b-20260121" !== isomorphicReactPackageVersion) throw Error( 'Incompatible React versions: The "react" and "react-dom" packages must have the exact same version. Instead got:\n - react: ' + (isomorphicReactPackageVersion + - "\n - react-dom: 19.3.0-experimental-d2908752-20260119\nLearn more: https://react.dev/warnings/version-mismatch") + "\n - react-dom: 19.3.0-experimental-b546603b-20260121\nLearn more: https://react.dev/warnings/version-mismatch") ); } ensureCorrectIsomorphicReactVersion(); @@ -7932,4 +7932,4 @@ exports.resumeToPipeableStream = function (children, postponedState, options) { } }; }; -exports.version = "19.3.0-experimental-d2908752-20260119"; +exports.version = "19.3.0-experimental-b546603b-20260121"; diff --git a/packages/next/src/compiled/react-dom-experimental/cjs/react-dom-server.edge.development.js b/packages/next/src/compiled/react-dom-experimental/cjs/react-dom-server.edge.development.js index 4b8c35680e5701..2b8dc2dfdc0f6c 100644 --- a/packages/next/src/compiled/react-dom-experimental/cjs/react-dom-server.edge.development.js +++ b/packages/next/src/compiled/react-dom-experimental/cjs/react-dom-server.edge.development.js @@ -9521,11 +9521,11 @@ } function ensureCorrectIsomorphicReactVersion() { var isomorphicReactPackageVersion = React.version; - if ("19.3.0-experimental-d2908752-20260119" !== isomorphicReactPackageVersion) + if ("19.3.0-experimental-b546603b-20260121" !== isomorphicReactPackageVersion) throw Error( 'Incompatible React versions: The "react" and "react-dom" packages must have the exact same version. Instead got:\n - react: ' + (isomorphicReactPackageVersion + - "\n - react-dom: 19.3.0-experimental-d2908752-20260119\nLearn more: https://react.dev/warnings/version-mismatch") + "\n - react-dom: 19.3.0-experimental-b546603b-20260121\nLearn more: https://react.dev/warnings/version-mismatch") ); } var React = require("next/dist/compiled/react-experimental"), @@ -11344,5 +11344,5 @@ startWork(request); }); }; - exports.version = "19.3.0-experimental-d2908752-20260119"; + exports.version = "19.3.0-experimental-b546603b-20260121"; })(); diff --git a/packages/next/src/compiled/react-dom-experimental/cjs/react-dom-server.edge.production.js b/packages/next/src/compiled/react-dom-experimental/cjs/react-dom-server.edge.production.js index 14d89a185b9da4..89b87045cb5688 100644 --- a/packages/next/src/compiled/react-dom-experimental/cjs/react-dom-server.edge.production.js +++ b/packages/next/src/compiled/react-dom-experimental/cjs/react-dom-server.edge.production.js @@ -7806,11 +7806,11 @@ function getPostponedState(request) { } function ensureCorrectIsomorphicReactVersion() { var isomorphicReactPackageVersion = React.version; - if ("19.3.0-experimental-d2908752-20260119" !== isomorphicReactPackageVersion) + if ("19.3.0-experimental-b546603b-20260121" !== isomorphicReactPackageVersion) throw Error( 'Incompatible React versions: The "react" and "react-dom" packages must have the exact same version. Instead got:\n - react: ' + (isomorphicReactPackageVersion + - "\n - react-dom: 19.3.0-experimental-d2908752-20260119\nLearn more: https://react.dev/warnings/version-mismatch") + "\n - react-dom: 19.3.0-experimental-b546603b-20260121\nLearn more: https://react.dev/warnings/version-mismatch") ); } ensureCorrectIsomorphicReactVersion(); @@ -8060,4 +8060,4 @@ exports.resumeAndPrerender = function (children, postponedState, options) { startWork(request); }); }; -exports.version = "19.3.0-experimental-d2908752-20260119"; +exports.version = "19.3.0-experimental-b546603b-20260121"; diff --git a/packages/next/src/compiled/react-dom-experimental/cjs/react-dom-server.node.development.js b/packages/next/src/compiled/react-dom-experimental/cjs/react-dom-server.node.development.js index b9591e58275dd2..5b2d9c9df8dedb 100644 --- a/packages/next/src/compiled/react-dom-experimental/cjs/react-dom-server.node.development.js +++ b/packages/next/src/compiled/react-dom-experimental/cjs/react-dom-server.node.development.js @@ -9381,11 +9381,11 @@ } function ensureCorrectIsomorphicReactVersion() { var isomorphicReactPackageVersion = React.version; - if ("19.3.0-experimental-d2908752-20260119" !== isomorphicReactPackageVersion) + if ("19.3.0-experimental-b546603b-20260121" !== isomorphicReactPackageVersion) throw Error( 'Incompatible React versions: The "react" and "react-dom" packages must have the exact same version. Instead got:\n - react: ' + (isomorphicReactPackageVersion + - "\n - react-dom: 19.3.0-experimental-d2908752-20260119\nLearn more: https://react.dev/warnings/version-mismatch") + "\n - react-dom: 19.3.0-experimental-b546603b-20260121\nLearn more: https://react.dev/warnings/version-mismatch") ); } function createDrainHandler(destination, request) { @@ -11510,5 +11510,5 @@ } }; }; - exports.version = "19.3.0-experimental-d2908752-20260119"; + exports.version = "19.3.0-experimental-b546603b-20260121"; })(); diff --git a/packages/next/src/compiled/react-dom-experimental/cjs/react-dom-server.node.production.js b/packages/next/src/compiled/react-dom-experimental/cjs/react-dom-server.node.production.js index be5dd27619d9d2..6cfa167bb0bbdd 100644 --- a/packages/next/src/compiled/react-dom-experimental/cjs/react-dom-server.node.production.js +++ b/packages/next/src/compiled/react-dom-experimental/cjs/react-dom-server.node.production.js @@ -7685,11 +7685,11 @@ function getPostponedState(request) { } function ensureCorrectIsomorphicReactVersion() { var isomorphicReactPackageVersion = React.version; - if ("19.3.0-experimental-d2908752-20260119" !== isomorphicReactPackageVersion) + if ("19.3.0-experimental-b546603b-20260121" !== isomorphicReactPackageVersion) throw Error( 'Incompatible React versions: The "react" and "react-dom" packages must have the exact same version. Instead got:\n - react: ' + (isomorphicReactPackageVersion + - "\n - react-dom: 19.3.0-experimental-d2908752-20260119\nLearn more: https://react.dev/warnings/version-mismatch") + "\n - react-dom: 19.3.0-experimental-b546603b-20260121\nLearn more: https://react.dev/warnings/version-mismatch") ); } ensureCorrectIsomorphicReactVersion(); @@ -8239,4 +8239,4 @@ exports.resumeToPipeableStream = function (children, postponedState, options) { } }; }; -exports.version = "19.3.0-experimental-d2908752-20260119"; +exports.version = "19.3.0-experimental-b546603b-20260121"; diff --git a/packages/next/src/compiled/react-dom-experimental/cjs/react-dom-unstable_testing.development.js b/packages/next/src/compiled/react-dom-experimental/cjs/react-dom-unstable_testing.development.js index 5189639b47e924..9cf1980aa00b74 100644 --- a/packages/next/src/compiled/react-dom-experimental/cjs/react-dom-unstable_testing.development.js +++ b/packages/next/src/compiled/react-dom-experimental/cjs/react-dom-unstable_testing.development.js @@ -123,18 +123,12 @@ ); } function getNearestMountedFiber(fiber) { - var node = fiber, - nearestMounted = fiber; - if (fiber.alternate) for (; node.return; ) node = node.return; - else { - fiber = node; - do - (node = fiber), - 0 !== (node.flags & 4098) && (nearestMounted = node.return), - (fiber = node.return); - while (fiber); - } - return 3 === node.tag ? nearestMounted : null; + for (var node = fiber, nextNode = node; nextNode && !nextNode.alternate; ) + (node = nextNode), + 0 !== (node.flags & 4098) && (fiber = node.return), + (nextNode = node.return); + for (; node.return; ) node = node.return; + return 3 === node.tag ? fiber : null; } function getSuspenseInstanceFromFiber(fiber) { if (13 === fiber.tag) { @@ -32999,11 +32993,11 @@ }; (function () { var isomorphicReactPackageVersion = React.version; - if ("19.3.0-experimental-d2908752-20260119" !== isomorphicReactPackageVersion) + if ("19.3.0-experimental-b546603b-20260121" !== isomorphicReactPackageVersion) throw Error( 'Incompatible React versions: The "react" and "react-dom" packages must have the exact same version. Instead got:\n - react: ' + (isomorphicReactPackageVersion + - "\n - react-dom: 19.3.0-experimental-d2908752-20260119\nLearn more: https://react.dev/warnings/version-mismatch") + "\n - react-dom: 19.3.0-experimental-b546603b-20260121\nLearn more: https://react.dev/warnings/version-mismatch") ); })(); ("function" === typeof Map && @@ -33040,10 +33034,10 @@ !(function () { var internals = { bundleType: 1, - version: "19.3.0-experimental-d2908752-20260119", + version: "19.3.0-experimental-b546603b-20260121", rendererPackageName: "react-dom", currentDispatcherRef: ReactSharedInternals, - reconcilerVersion: "19.3.0-experimental-d2908752-20260119" + reconcilerVersion: "19.3.0-experimental-b546603b-20260121" }; internals.overrideHookState = overrideHookState; internals.overrideHookStateDeletePath = overrideHookStateDeletePath; @@ -33357,5 +33351,5 @@ } }; }; - exports.version = "19.3.0-experimental-d2908752-20260119"; + exports.version = "19.3.0-experimental-b546603b-20260121"; })(); diff --git a/packages/next/src/compiled/react-dom-experimental/cjs/react-dom-unstable_testing.production.js b/packages/next/src/compiled/react-dom-experimental/cjs/react-dom-unstable_testing.production.js index d7e63c4ef634dc..0c1a12ec7559d3 100644 --- a/packages/next/src/compiled/react-dom-experimental/cjs/react-dom-unstable_testing.production.js +++ b/packages/next/src/compiled/react-dom-experimental/cjs/react-dom-unstable_testing.production.js @@ -37,18 +37,12 @@ function isValidContainer(node) { ); } function getNearestMountedFiber(fiber) { - var node = fiber, - nearestMounted = fiber; - if (fiber.alternate) for (; node.return; ) node = node.return; - else { - fiber = node; - do - (node = fiber), - 0 !== (node.flags & 4098) && (nearestMounted = node.return), - (fiber = node.return); - while (fiber); - } - return 3 === node.tag ? nearestMounted : null; + for (var node = fiber, nextNode = node; nextNode && !nextNode.alternate; ) + (node = nextNode), + 0 !== (node.flags & 4098) && (fiber = node.return), + (nextNode = node.return); + for (; node.return; ) node = node.return; + return 3 === node.tag ? fiber : null; } function getSuspenseInstanceFromFiber(fiber) { if (13 === fiber.tag) { @@ -20147,14 +20141,14 @@ ReactDOMHydrationRoot.prototype.unstable_scheduleHydration = function (target) { }; var isomorphicReactPackageVersion$jscomp$inline_2266 = React.version; if ( - "19.3.0-experimental-d2908752-20260119" !== + "19.3.0-experimental-b546603b-20260121" !== isomorphicReactPackageVersion$jscomp$inline_2266 ) throw Error( formatProdErrorMessage( 527, isomorphicReactPackageVersion$jscomp$inline_2266, - "19.3.0-experimental-d2908752-20260119" + "19.3.0-experimental-b546603b-20260121" ) ); ReactDOMSharedInternals.findDOMNode = function (componentOrElement) { @@ -20176,10 +20170,10 @@ ReactDOMSharedInternals.findDOMNode = function (componentOrElement) { }; var internals$jscomp$inline_2974 = { bundleType: 0, - version: "19.3.0-experimental-d2908752-20260119", + version: "19.3.0-experimental-b546603b-20260121", rendererPackageName: "react-dom", currentDispatcherRef: ReactSharedInternals, - reconcilerVersion: "19.3.0-experimental-d2908752-20260119" + reconcilerVersion: "19.3.0-experimental-b546603b-20260121" }; if ("undefined" !== typeof __REACT_DEVTOOLS_GLOBAL_HOOK__) { var hook$jscomp$inline_2975 = __REACT_DEVTOOLS_GLOBAL_HOOK__; @@ -20437,4 +20431,4 @@ exports.observeVisibleRects = function ( } }; }; -exports.version = "19.3.0-experimental-d2908752-20260119"; +exports.version = "19.3.0-experimental-b546603b-20260121"; diff --git a/packages/next/src/compiled/react-dom-experimental/cjs/react-dom.development.js b/packages/next/src/compiled/react-dom-experimental/cjs/react-dom.development.js index 18873a3ed8c52d..8ae346db9d3ac9 100644 --- a/packages/next/src/compiled/react-dom-experimental/cjs/react-dom.development.js +++ b/packages/next/src/compiled/react-dom-experimental/cjs/react-dom.development.js @@ -422,7 +422,7 @@ exports.useFormStatus = function () { return resolveDispatcher().useHostTransitionStatus(); }; - exports.version = "19.3.0-experimental-d2908752-20260119"; + exports.version = "19.3.0-experimental-b546603b-20260121"; "undefined" !== typeof __REACT_DEVTOOLS_GLOBAL_HOOK__ && "function" === typeof __REACT_DEVTOOLS_GLOBAL_HOOK__.registerInternalModuleStop && diff --git a/packages/next/src/compiled/react-dom-experimental/cjs/react-dom.production.js b/packages/next/src/compiled/react-dom-experimental/cjs/react-dom.production.js index b1e948d032ca96..40507ecbd03987 100644 --- a/packages/next/src/compiled/react-dom-experimental/cjs/react-dom.production.js +++ b/packages/next/src/compiled/react-dom-experimental/cjs/react-dom.production.js @@ -213,4 +213,4 @@ exports.useFormState = function (action, initialState, permalink) { exports.useFormStatus = function () { return ReactSharedInternals.H.useHostTransitionStatus(); }; -exports.version = "19.3.0-experimental-d2908752-20260119"; +exports.version = "19.3.0-experimental-b546603b-20260121"; diff --git a/packages/next/src/compiled/react-dom-experimental/cjs/react-dom.react-server.development.js b/packages/next/src/compiled/react-dom-experimental/cjs/react-dom.react-server.development.js index e4ba7e033838a5..f2384b4d5bed94 100644 --- a/packages/next/src/compiled/react-dom-experimental/cjs/react-dom.react-server.development.js +++ b/packages/next/src/compiled/react-dom-experimental/cjs/react-dom.react-server.development.js @@ -336,5 +336,5 @@ })) : Internals.d.m(href)); }; - exports.version = "19.3.0-experimental-d2908752-20260119"; + exports.version = "19.3.0-experimental-b546603b-20260121"; })(); diff --git a/packages/next/src/compiled/react-dom-experimental/cjs/react-dom.react-server.production.js b/packages/next/src/compiled/react-dom-experimental/cjs/react-dom.react-server.production.js index 2913ae6b2ae1ab..20dfb12898a1b4 100644 --- a/packages/next/src/compiled/react-dom-experimental/cjs/react-dom.react-server.production.js +++ b/packages/next/src/compiled/react-dom-experimental/cjs/react-dom.react-server.production.js @@ -149,4 +149,4 @@ exports.preloadModule = function (href, options) { }); } else Internals.d.m(href); }; -exports.version = "19.3.0-experimental-d2908752-20260119"; +exports.version = "19.3.0-experimental-b546603b-20260121"; diff --git a/packages/next/src/compiled/react-dom-experimental/package.json b/packages/next/src/compiled/react-dom-experimental/package.json index 05ce326dafc786..2efe917684c193 100644 --- a/packages/next/src/compiled/react-dom-experimental/package.json +++ b/packages/next/src/compiled/react-dom-experimental/package.json @@ -72,10 +72,10 @@ "./package.json": "./package.json" }, "dependencies": { - "scheduler": "0.0.0-experimental-d2908752-20260119" + "scheduler": "0.0.0-experimental-b546603b-20260121" }, "peerDependencies": { - "react": "0.0.0-experimental-d2908752-20260119" + "react": "0.0.0-experimental-b546603b-20260121" }, "browser": { "./server.js": "./server.browser.js", diff --git a/packages/next/src/compiled/react-dom/cjs/react-dom-client.development.js b/packages/next/src/compiled/react-dom/cjs/react-dom-client.development.js index a5470d05695e8c..0f4e7b84059db3 100644 --- a/packages/next/src/compiled/react-dom/cjs/react-dom-client.development.js +++ b/packages/next/src/compiled/react-dom/cjs/react-dom-client.development.js @@ -123,18 +123,12 @@ ); } function getNearestMountedFiber(fiber) { - var node = fiber, - nearestMounted = fiber; - if (fiber.alternate) for (; node.return; ) node = node.return; - else { - fiber = node; - do - (node = fiber), - 0 !== (node.flags & 4098) && (nearestMounted = node.return), - (fiber = node.return); - while (fiber); - } - return 3 === node.tag ? nearestMounted : null; + for (var node = fiber, nextNode = node; nextNode && !nextNode.alternate; ) + (node = nextNode), + 0 !== (node.flags & 4098) && (fiber = node.return), + (nextNode = node.return); + for (; node.return; ) node = node.return; + return 3 === node.tag ? fiber : null; } function getSuspenseInstanceFromFiber(fiber) { if (13 === fiber.tag) { @@ -30428,11 +30422,11 @@ }; (function () { var isomorphicReactPackageVersion = React.version; - if ("19.3.0-canary-d2908752-20260119" !== isomorphicReactPackageVersion) + if ("19.3.0-canary-b546603b-20260121" !== isomorphicReactPackageVersion) throw Error( 'Incompatible React versions: The "react" and "react-dom" packages must have the exact same version. Instead got:\n - react: ' + (isomorphicReactPackageVersion + - "\n - react-dom: 19.3.0-canary-d2908752-20260119\nLearn more: https://react.dev/warnings/version-mismatch") + "\n - react-dom: 19.3.0-canary-b546603b-20260121\nLearn more: https://react.dev/warnings/version-mismatch") ); })(); ("function" === typeof Map && @@ -30469,10 +30463,10 @@ !(function () { var internals = { bundleType: 1, - version: "19.3.0-canary-d2908752-20260119", + version: "19.3.0-canary-b546603b-20260121", rendererPackageName: "react-dom", currentDispatcherRef: ReactSharedInternals, - reconcilerVersion: "19.3.0-canary-d2908752-20260119" + reconcilerVersion: "19.3.0-canary-b546603b-20260121" }; internals.overrideHookState = overrideHookState; internals.overrideHookStateDeletePath = overrideHookStateDeletePath; @@ -30610,7 +30604,7 @@ listenToAllSupportedEvents(container); return new ReactDOMHydrationRoot(initialChildren); }; - exports.version = "19.3.0-canary-d2908752-20260119"; + exports.version = "19.3.0-canary-b546603b-20260121"; "undefined" !== typeof __REACT_DEVTOOLS_GLOBAL_HOOK__ && "function" === typeof __REACT_DEVTOOLS_GLOBAL_HOOK__.registerInternalModuleStop && diff --git a/packages/next/src/compiled/react-dom/cjs/react-dom-client.production.js b/packages/next/src/compiled/react-dom/cjs/react-dom-client.production.js index 03d9c337181e33..a6b9c11c6ea90c 100644 --- a/packages/next/src/compiled/react-dom/cjs/react-dom-client.production.js +++ b/packages/next/src/compiled/react-dom/cjs/react-dom-client.production.js @@ -37,18 +37,12 @@ function isValidContainer(node) { ); } function getNearestMountedFiber(fiber) { - var node = fiber, - nearestMounted = fiber; - if (fiber.alternate) for (; node.return; ) node = node.return; - else { - fiber = node; - do - (node = fiber), - 0 !== (node.flags & 4098) && (nearestMounted = node.return), - (fiber = node.return); - while (fiber); - } - return 3 === node.tag ? nearestMounted : null; + for (var node = fiber, nextNode = node; nextNode && !nextNode.alternate; ) + (node = nextNode), + 0 !== (node.flags & 4098) && (fiber = node.return), + (nextNode = node.return); + for (; node.return; ) node = node.return; + return 3 === node.tag ? fiber : null; } function getSuspenseInstanceFromFiber(fiber) { if (13 === fiber.tag) { @@ -18034,14 +18028,14 @@ ReactDOMHydrationRoot.prototype.unstable_scheduleHydration = function (target) { }; var isomorphicReactPackageVersion$jscomp$inline_2044 = React.version; if ( - "19.3.0-canary-d2908752-20260119" !== + "19.3.0-canary-b546603b-20260121" !== isomorphicReactPackageVersion$jscomp$inline_2044 ) throw Error( formatProdErrorMessage( 527, isomorphicReactPackageVersion$jscomp$inline_2044, - "19.3.0-canary-d2908752-20260119" + "19.3.0-canary-b546603b-20260121" ) ); ReactDOMSharedInternals.findDOMNode = function (componentOrElement) { @@ -18063,10 +18057,10 @@ ReactDOMSharedInternals.findDOMNode = function (componentOrElement) { }; var internals$jscomp$inline_2634 = { bundleType: 0, - version: "19.3.0-canary-d2908752-20260119", + version: "19.3.0-canary-b546603b-20260121", rendererPackageName: "react-dom", currentDispatcherRef: ReactSharedInternals, - reconcilerVersion: "19.3.0-canary-d2908752-20260119" + reconcilerVersion: "19.3.0-canary-b546603b-20260121" }; if ("undefined" !== typeof __REACT_DEVTOOLS_GLOBAL_HOOK__) { var hook$jscomp$inline_2635 = __REACT_DEVTOOLS_GLOBAL_HOOK__; @@ -18164,4 +18158,4 @@ exports.hydrateRoot = function (container, initialChildren, options) { listenToAllSupportedEvents(container); return new ReactDOMHydrationRoot(initialChildren); }; -exports.version = "19.3.0-canary-d2908752-20260119"; +exports.version = "19.3.0-canary-b546603b-20260121"; diff --git a/packages/next/src/compiled/react-dom/cjs/react-dom-profiling.development.js b/packages/next/src/compiled/react-dom/cjs/react-dom-profiling.development.js index 62d22c48fe9e80..b346255bbc7356 100644 --- a/packages/next/src/compiled/react-dom/cjs/react-dom-profiling.development.js +++ b/packages/next/src/compiled/react-dom/cjs/react-dom-profiling.development.js @@ -123,18 +123,12 @@ ); } function getNearestMountedFiber(fiber) { - var node = fiber, - nearestMounted = fiber; - if (fiber.alternate) for (; node.return; ) node = node.return; - else { - fiber = node; - do - (node = fiber), - 0 !== (node.flags & 4098) && (nearestMounted = node.return), - (fiber = node.return); - while (fiber); - } - return 3 === node.tag ? nearestMounted : null; + for (var node = fiber, nextNode = node; nextNode && !nextNode.alternate; ) + (node = nextNode), + 0 !== (node.flags & 4098) && (fiber = node.return), + (nextNode = node.return); + for (; node.return; ) node = node.return; + return 3 === node.tag ? fiber : null; } function getSuspenseInstanceFromFiber(fiber) { if (13 === fiber.tag) { @@ -30486,11 +30480,11 @@ }; (function () { var isomorphicReactPackageVersion = React.version; - if ("19.3.0-canary-d2908752-20260119" !== isomorphicReactPackageVersion) + if ("19.3.0-canary-b546603b-20260121" !== isomorphicReactPackageVersion) throw Error( 'Incompatible React versions: The "react" and "react-dom" packages must have the exact same version. Instead got:\n - react: ' + (isomorphicReactPackageVersion + - "\n - react-dom: 19.3.0-canary-d2908752-20260119\nLearn more: https://react.dev/warnings/version-mismatch") + "\n - react-dom: 19.3.0-canary-b546603b-20260121\nLearn more: https://react.dev/warnings/version-mismatch") ); })(); ("function" === typeof Map && @@ -30527,10 +30521,10 @@ !(function () { var internals = { bundleType: 1, - version: "19.3.0-canary-d2908752-20260119", + version: "19.3.0-canary-b546603b-20260121", rendererPackageName: "react-dom", currentDispatcherRef: ReactSharedInternals, - reconcilerVersion: "19.3.0-canary-d2908752-20260119" + reconcilerVersion: "19.3.0-canary-b546603b-20260121" }; internals.overrideHookState = overrideHookState; internals.overrideHookStateDeletePath = overrideHookStateDeletePath; @@ -30998,7 +30992,7 @@ exports.useFormStatus = function () { return resolveDispatcher().useHostTransitionStatus(); }; - exports.version = "19.3.0-canary-d2908752-20260119"; + exports.version = "19.3.0-canary-b546603b-20260121"; "undefined" !== typeof __REACT_DEVTOOLS_GLOBAL_HOOK__ && "function" === typeof __REACT_DEVTOOLS_GLOBAL_HOOK__.registerInternalModuleStop && diff --git a/packages/next/src/compiled/react-dom/cjs/react-dom-profiling.profiling.js b/packages/next/src/compiled/react-dom/cjs/react-dom-profiling.profiling.js index 338bcee953913f..c78bd0e564ca83 100644 --- a/packages/next/src/compiled/react-dom/cjs/react-dom-profiling.profiling.js +++ b/packages/next/src/compiled/react-dom/cjs/react-dom-profiling.profiling.js @@ -41,18 +41,12 @@ function isValidContainer(node) { ); } function getNearestMountedFiber(fiber) { - var node = fiber, - nearestMounted = fiber; - if (fiber.alternate) for (; node.return; ) node = node.return; - else { - fiber = node; - do - (node = fiber), - 0 !== (node.flags & 4098) && (nearestMounted = node.return), - (fiber = node.return); - while (fiber); - } - return 3 === node.tag ? nearestMounted : null; + for (var node = fiber, nextNode = node; nextNode && !nextNode.alternate; ) + (node = nextNode), + 0 !== (node.flags & 4098) && (fiber = node.return), + (nextNode = node.return); + for (; node.return; ) node = node.return; + return 3 === node.tag ? fiber : null; } function getSuspenseInstanceFromFiber(fiber) { if (13 === fiber.tag) { @@ -19963,14 +19957,14 @@ ReactDOMHydrationRoot.prototype.unstable_scheduleHydration = function (target) { }; var isomorphicReactPackageVersion$jscomp$inline_2348 = React.version; if ( - "19.3.0-canary-d2908752-20260119" !== + "19.3.0-canary-b546603b-20260121" !== isomorphicReactPackageVersion$jscomp$inline_2348 ) throw Error( formatProdErrorMessage( 527, isomorphicReactPackageVersion$jscomp$inline_2348, - "19.3.0-canary-d2908752-20260119" + "19.3.0-canary-b546603b-20260121" ) ); ReactDOMSharedInternals.findDOMNode = function (componentOrElement) { @@ -19992,10 +19986,10 @@ ReactDOMSharedInternals.findDOMNode = function (componentOrElement) { }; var internals$jscomp$inline_2951 = { bundleType: 0, - version: "19.3.0-canary-d2908752-20260119", + version: "19.3.0-canary-b546603b-20260121", rendererPackageName: "react-dom", currentDispatcherRef: ReactSharedInternals, - reconcilerVersion: "19.3.0-canary-d2908752-20260119" + reconcilerVersion: "19.3.0-canary-b546603b-20260121" }; if ("undefined" !== typeof __REACT_DEVTOOLS_GLOBAL_HOOK__) { var hook$jscomp$inline_2952 = __REACT_DEVTOOLS_GLOBAL_HOOK__; @@ -20254,7 +20248,7 @@ exports.useFormState = function (action, initialState, permalink) { exports.useFormStatus = function () { return ReactSharedInternals.H.useHostTransitionStatus(); }; -exports.version = "19.3.0-canary-d2908752-20260119"; +exports.version = "19.3.0-canary-b546603b-20260121"; "undefined" !== typeof __REACT_DEVTOOLS_GLOBAL_HOOK__ && "function" === typeof __REACT_DEVTOOLS_GLOBAL_HOOK__.registerInternalModuleStop && diff --git a/packages/next/src/compiled/react-dom/cjs/react-dom-server-legacy.browser.development.js b/packages/next/src/compiled/react-dom/cjs/react-dom-server-legacy.browser.development.js index 709f21eaae8028..c1291e1347b1c7 100644 --- a/packages/next/src/compiled/react-dom/cjs/react-dom-server-legacy.browser.development.js +++ b/packages/next/src/compiled/react-dom/cjs/react-dom-server-legacy.browser.development.js @@ -10140,5 +10140,5 @@ 'The server used "renderToString" which does not support Suspense. If you intended for this Suspense boundary to render the fallback content on the server consider throwing an Error somewhere within the Suspense boundary. If you intended to have the server wait for the suspended component please switch to "renderToReadableStream" which supports Suspense on the server' ); }; - exports.version = "19.3.0-canary-d2908752-20260119"; + exports.version = "19.3.0-canary-b546603b-20260121"; })(); diff --git a/packages/next/src/compiled/react-dom/cjs/react-dom-server-legacy.browser.production.js b/packages/next/src/compiled/react-dom/cjs/react-dom-server-legacy.browser.production.js index 401f929dbf1389..4822e3443c9a3f 100644 --- a/packages/next/src/compiled/react-dom/cjs/react-dom-server-legacy.browser.production.js +++ b/packages/next/src/compiled/react-dom/cjs/react-dom-server-legacy.browser.production.js @@ -6763,4 +6763,4 @@ exports.renderToString = function (children, options) { 'The server used "renderToString" which does not support Suspense. If you intended for this Suspense boundary to render the fallback content on the server consider throwing an Error somewhere within the Suspense boundary. If you intended to have the server wait for the suspended component please switch to "renderToReadableStream" which supports Suspense on the server' ); }; -exports.version = "19.3.0-canary-d2908752-20260119"; +exports.version = "19.3.0-canary-b546603b-20260121"; diff --git a/packages/next/src/compiled/react-dom/cjs/react-dom-server-legacy.node.development.js b/packages/next/src/compiled/react-dom/cjs/react-dom-server-legacy.node.development.js index 29b170bc38e51f..5db8b04f9085f6 100644 --- a/packages/next/src/compiled/react-dom/cjs/react-dom-server-legacy.node.development.js +++ b/packages/next/src/compiled/react-dom/cjs/react-dom-server-legacy.node.development.js @@ -10140,5 +10140,5 @@ 'The server used "renderToString" which does not support Suspense. If you intended for this Suspense boundary to render the fallback content on the server consider throwing an Error somewhere within the Suspense boundary. If you intended to have the server wait for the suspended component please switch to "renderToPipeableStream" which supports Suspense on the server' ); }; - exports.version = "19.3.0-canary-d2908752-20260119"; + exports.version = "19.3.0-canary-b546603b-20260121"; })(); diff --git a/packages/next/src/compiled/react-dom/cjs/react-dom-server-legacy.node.production.js b/packages/next/src/compiled/react-dom/cjs/react-dom-server-legacy.node.production.js index c29a02c5c3c292..eb9e005e0f856f 100644 --- a/packages/next/src/compiled/react-dom/cjs/react-dom-server-legacy.node.production.js +++ b/packages/next/src/compiled/react-dom/cjs/react-dom-server-legacy.node.production.js @@ -6855,4 +6855,4 @@ exports.renderToString = function (children, options) { 'The server used "renderToString" which does not support Suspense. If you intended for this Suspense boundary to render the fallback content on the server consider throwing an Error somewhere within the Suspense boundary. If you intended to have the server wait for the suspended component please switch to "renderToPipeableStream" which supports Suspense on the server' ); }; -exports.version = "19.3.0-canary-d2908752-20260119"; +exports.version = "19.3.0-canary-b546603b-20260121"; diff --git a/packages/next/src/compiled/react-dom/cjs/react-dom-server.browser.development.js b/packages/next/src/compiled/react-dom/cjs/react-dom-server.browser.development.js index 050ab85131f43a..03b5d0901698bc 100644 --- a/packages/next/src/compiled/react-dom/cjs/react-dom-server.browser.development.js +++ b/packages/next/src/compiled/react-dom/cjs/react-dom-server.browser.development.js @@ -9103,11 +9103,11 @@ } function ensureCorrectIsomorphicReactVersion() { var isomorphicReactPackageVersion = React.version; - if ("19.3.0-canary-d2908752-20260119" !== isomorphicReactPackageVersion) + if ("19.3.0-canary-b546603b-20260121" !== isomorphicReactPackageVersion) throw Error( 'Incompatible React versions: The "react" and "react-dom" packages must have the exact same version. Instead got:\n - react: ' + (isomorphicReactPackageVersion + - "\n - react-dom: 19.3.0-canary-d2908752-20260119\nLearn more: https://react.dev/warnings/version-mismatch") + "\n - react-dom: 19.3.0-canary-b546603b-20260121\nLearn more: https://react.dev/warnings/version-mismatch") ); } var React = require("next/dist/compiled/react"), @@ -10913,5 +10913,5 @@ startWork(request); }); }; - exports.version = "19.3.0-canary-d2908752-20260119"; + exports.version = "19.3.0-canary-b546603b-20260121"; })(); diff --git a/packages/next/src/compiled/react-dom/cjs/react-dom-server.browser.production.js b/packages/next/src/compiled/react-dom/cjs/react-dom-server.browser.production.js index 4916b3cf15b69f..8b281ea480087b 100644 --- a/packages/next/src/compiled/react-dom/cjs/react-dom-server.browser.production.js +++ b/packages/next/src/compiled/react-dom/cjs/react-dom-server.browser.production.js @@ -7365,12 +7365,12 @@ function getPostponedState(request) { } function ensureCorrectIsomorphicReactVersion() { var isomorphicReactPackageVersion = React.version; - if ("19.3.0-canary-d2908752-20260119" !== isomorphicReactPackageVersion) + if ("19.3.0-canary-b546603b-20260121" !== isomorphicReactPackageVersion) throw Error( formatProdErrorMessage( 527, isomorphicReactPackageVersion, - "19.3.0-canary-d2908752-20260119" + "19.3.0-canary-b546603b-20260121" ) ); } @@ -7621,4 +7621,4 @@ exports.resumeAndPrerender = function (children, postponedState, options) { startWork(request); }); }; -exports.version = "19.3.0-canary-d2908752-20260119"; +exports.version = "19.3.0-canary-b546603b-20260121"; diff --git a/packages/next/src/compiled/react-dom/cjs/react-dom-server.bun.production.js b/packages/next/src/compiled/react-dom/cjs/react-dom-server.bun.production.js index 5b61da1ba7a735..9aff7043adce63 100644 --- a/packages/next/src/compiled/react-dom/cjs/react-dom-server.bun.production.js +++ b/packages/next/src/compiled/react-dom/cjs/react-dom-server.bun.production.js @@ -7073,11 +7073,11 @@ function getPostponedState(request) { } function ensureCorrectIsomorphicReactVersion() { var isomorphicReactPackageVersion = React.version; - if ("19.3.0-canary-d2908752-20260119" !== isomorphicReactPackageVersion) + if ("19.3.0-canary-b546603b-20260121" !== isomorphicReactPackageVersion) throw Error( 'Incompatible React versions: The "react" and "react-dom" packages must have the exact same version. Instead got:\n - react: ' + (isomorphicReactPackageVersion + - "\n - react-dom: 19.3.0-canary-d2908752-20260119\nLearn more: https://react.dev/warnings/version-mismatch") + "\n - react-dom: 19.3.0-canary-b546603b-20260121\nLearn more: https://react.dev/warnings/version-mismatch") ); } ensureCorrectIsomorphicReactVersion(); @@ -7622,4 +7622,4 @@ exports.resumeToPipeableStream = function (children, postponedState, options) { } }; }; -exports.version = "19.3.0-canary-d2908752-20260119"; +exports.version = "19.3.0-canary-b546603b-20260121"; diff --git a/packages/next/src/compiled/react-dom/cjs/react-dom-server.edge.development.js b/packages/next/src/compiled/react-dom/cjs/react-dom-server.edge.development.js index c91becbbdf82a6..93e9d5beb16bae 100644 --- a/packages/next/src/compiled/react-dom/cjs/react-dom-server.edge.development.js +++ b/packages/next/src/compiled/react-dom/cjs/react-dom-server.edge.development.js @@ -9126,11 +9126,11 @@ } function ensureCorrectIsomorphicReactVersion() { var isomorphicReactPackageVersion = React.version; - if ("19.3.0-canary-d2908752-20260119" !== isomorphicReactPackageVersion) + if ("19.3.0-canary-b546603b-20260121" !== isomorphicReactPackageVersion) throw Error( 'Incompatible React versions: The "react" and "react-dom" packages must have the exact same version. Instead got:\n - react: ' + (isomorphicReactPackageVersion + - "\n - react-dom: 19.3.0-canary-d2908752-20260119\nLearn more: https://react.dev/warnings/version-mismatch") + "\n - react-dom: 19.3.0-canary-b546603b-20260121\nLearn more: https://react.dev/warnings/version-mismatch") ); } var React = require("next/dist/compiled/react"), @@ -10932,5 +10932,5 @@ startWork(request); }); }; - exports.version = "19.3.0-canary-d2908752-20260119"; + exports.version = "19.3.0-canary-b546603b-20260121"; })(); diff --git a/packages/next/src/compiled/react-dom/cjs/react-dom-server.edge.production.js b/packages/next/src/compiled/react-dom/cjs/react-dom-server.edge.production.js index d2eb63c7fef8c9..91869d2d0a9dd7 100644 --- a/packages/next/src/compiled/react-dom/cjs/react-dom-server.edge.production.js +++ b/packages/next/src/compiled/react-dom/cjs/react-dom-server.edge.production.js @@ -7472,11 +7472,11 @@ function getPostponedState(request) { } function ensureCorrectIsomorphicReactVersion() { var isomorphicReactPackageVersion = React.version; - if ("19.3.0-canary-d2908752-20260119" !== isomorphicReactPackageVersion) + if ("19.3.0-canary-b546603b-20260121" !== isomorphicReactPackageVersion) throw Error( 'Incompatible React versions: The "react" and "react-dom" packages must have the exact same version. Instead got:\n - react: ' + (isomorphicReactPackageVersion + - "\n - react-dom: 19.3.0-canary-d2908752-20260119\nLearn more: https://react.dev/warnings/version-mismatch") + "\n - react-dom: 19.3.0-canary-b546603b-20260121\nLearn more: https://react.dev/warnings/version-mismatch") ); } ensureCorrectIsomorphicReactVersion(); @@ -7726,4 +7726,4 @@ exports.resumeAndPrerender = function (children, postponedState, options) { startWork(request); }); }; -exports.version = "19.3.0-canary-d2908752-20260119"; +exports.version = "19.3.0-canary-b546603b-20260121"; diff --git a/packages/next/src/compiled/react-dom/cjs/react-dom-server.node.development.js b/packages/next/src/compiled/react-dom/cjs/react-dom-server.node.development.js index 45c3893dcb86a2..87b600596905b6 100644 --- a/packages/next/src/compiled/react-dom/cjs/react-dom-server.node.development.js +++ b/packages/next/src/compiled/react-dom/cjs/react-dom-server.node.development.js @@ -9000,11 +9000,11 @@ } function ensureCorrectIsomorphicReactVersion() { var isomorphicReactPackageVersion = React.version; - if ("19.3.0-canary-d2908752-20260119" !== isomorphicReactPackageVersion) + if ("19.3.0-canary-b546603b-20260121" !== isomorphicReactPackageVersion) throw Error( 'Incompatible React versions: The "react" and "react-dom" packages must have the exact same version. Instead got:\n - react: ' + (isomorphicReactPackageVersion + - "\n - react-dom: 19.3.0-canary-d2908752-20260119\nLearn more: https://react.dev/warnings/version-mismatch") + "\n - react-dom: 19.3.0-canary-b546603b-20260121\nLearn more: https://react.dev/warnings/version-mismatch") ); } function createDrainHandler(destination, request) { @@ -11112,5 +11112,5 @@ } }; }; - exports.version = "19.3.0-canary-d2908752-20260119"; + exports.version = "19.3.0-canary-b546603b-20260121"; })(); diff --git a/packages/next/src/compiled/react-dom/cjs/react-dom-server.node.production.js b/packages/next/src/compiled/react-dom/cjs/react-dom-server.node.production.js index b352adde5b49da..2f5dff6158c924 100644 --- a/packages/next/src/compiled/react-dom/cjs/react-dom-server.node.production.js +++ b/packages/next/src/compiled/react-dom/cjs/react-dom-server.node.production.js @@ -7363,11 +7363,11 @@ function getPostponedState(request) { } function ensureCorrectIsomorphicReactVersion() { var isomorphicReactPackageVersion = React.version; - if ("19.3.0-canary-d2908752-20260119" !== isomorphicReactPackageVersion) + if ("19.3.0-canary-b546603b-20260121" !== isomorphicReactPackageVersion) throw Error( 'Incompatible React versions: The "react" and "react-dom" packages must have the exact same version. Instead got:\n - react: ' + (isomorphicReactPackageVersion + - "\n - react-dom: 19.3.0-canary-d2908752-20260119\nLearn more: https://react.dev/warnings/version-mismatch") + "\n - react-dom: 19.3.0-canary-b546603b-20260121\nLearn more: https://react.dev/warnings/version-mismatch") ); } ensureCorrectIsomorphicReactVersion(); @@ -7917,4 +7917,4 @@ exports.resumeToPipeableStream = function (children, postponedState, options) { } }; }; -exports.version = "19.3.0-canary-d2908752-20260119"; +exports.version = "19.3.0-canary-b546603b-20260121"; diff --git a/packages/next/src/compiled/react-dom/cjs/react-dom.development.js b/packages/next/src/compiled/react-dom/cjs/react-dom.development.js index 722c031ee33572..4ac92be2b13776 100644 --- a/packages/next/src/compiled/react-dom/cjs/react-dom.development.js +++ b/packages/next/src/compiled/react-dom/cjs/react-dom.development.js @@ -422,7 +422,7 @@ exports.useFormStatus = function () { return resolveDispatcher().useHostTransitionStatus(); }; - exports.version = "19.3.0-canary-d2908752-20260119"; + exports.version = "19.3.0-canary-b546603b-20260121"; "undefined" !== typeof __REACT_DEVTOOLS_GLOBAL_HOOK__ && "function" === typeof __REACT_DEVTOOLS_GLOBAL_HOOK__.registerInternalModuleStop && diff --git a/packages/next/src/compiled/react-dom/cjs/react-dom.production.js b/packages/next/src/compiled/react-dom/cjs/react-dom.production.js index c99d32640eeb49..171ccec7d886c6 100644 --- a/packages/next/src/compiled/react-dom/cjs/react-dom.production.js +++ b/packages/next/src/compiled/react-dom/cjs/react-dom.production.js @@ -213,4 +213,4 @@ exports.useFormState = function (action, initialState, permalink) { exports.useFormStatus = function () { return ReactSharedInternals.H.useHostTransitionStatus(); }; -exports.version = "19.3.0-canary-d2908752-20260119"; +exports.version = "19.3.0-canary-b546603b-20260121"; diff --git a/packages/next/src/compiled/react-dom/cjs/react-dom.react-server.development.js b/packages/next/src/compiled/react-dom/cjs/react-dom.react-server.development.js index 1b22fdfe5cae21..2ba519544382fa 100644 --- a/packages/next/src/compiled/react-dom/cjs/react-dom.react-server.development.js +++ b/packages/next/src/compiled/react-dom/cjs/react-dom.react-server.development.js @@ -336,5 +336,5 @@ })) : Internals.d.m(href)); }; - exports.version = "19.3.0-canary-d2908752-20260119"; + exports.version = "19.3.0-canary-b546603b-20260121"; })(); diff --git a/packages/next/src/compiled/react-dom/cjs/react-dom.react-server.production.js b/packages/next/src/compiled/react-dom/cjs/react-dom.react-server.production.js index 877e0e55a0b3c6..0cab99d0a03b12 100644 --- a/packages/next/src/compiled/react-dom/cjs/react-dom.react-server.production.js +++ b/packages/next/src/compiled/react-dom/cjs/react-dom.react-server.production.js @@ -149,4 +149,4 @@ exports.preloadModule = function (href, options) { }); } else Internals.d.m(href); }; -exports.version = "19.3.0-canary-d2908752-20260119"; +exports.version = "19.3.0-canary-b546603b-20260121"; diff --git a/packages/next/src/compiled/react-dom/package.json b/packages/next/src/compiled/react-dom/package.json index 2979fa51629f2e..9d34d75c575f70 100644 --- a/packages/next/src/compiled/react-dom/package.json +++ b/packages/next/src/compiled/react-dom/package.json @@ -67,10 +67,10 @@ "./package.json": "./package.json" }, "dependencies": { - "scheduler": "0.28.0-canary-d2908752-20260119" + "scheduler": "0.28.0-canary-b546603b-20260121" }, "peerDependencies": { - "react": "19.3.0-canary-d2908752-20260119" + "react": "19.3.0-canary-b546603b-20260121" }, "browser": { "./server.js": "./server.browser.js", diff --git a/packages/next/src/compiled/react-experimental/cjs/react.development.js b/packages/next/src/compiled/react-experimental/cjs/react.development.js index 499203be686e3b..411ab9d807cff5 100644 --- a/packages/next/src/compiled/react-experimental/cjs/react.development.js +++ b/packages/next/src/compiled/react-experimental/cjs/react.development.js @@ -1391,7 +1391,7 @@ exports.useTransition = function () { return resolveDispatcher().useTransition(); }; - exports.version = "19.3.0-experimental-d2908752-20260119"; + exports.version = "19.3.0-experimental-b546603b-20260121"; "undefined" !== typeof __REACT_DEVTOOLS_GLOBAL_HOOK__ && "function" === typeof __REACT_DEVTOOLS_GLOBAL_HOOK__.registerInternalModuleStop && diff --git a/packages/next/src/compiled/react-experimental/cjs/react.production.js b/packages/next/src/compiled/react-experimental/cjs/react.production.js index 0a55e07464a1e8..2bbdbd71c62c30 100644 --- a/packages/next/src/compiled/react-experimental/cjs/react.production.js +++ b/packages/next/src/compiled/react-experimental/cjs/react.production.js @@ -613,4 +613,4 @@ exports.useSyncExternalStore = function ( exports.useTransition = function () { return ReactSharedInternals.H.useTransition(); }; -exports.version = "19.3.0-experimental-d2908752-20260119"; +exports.version = "19.3.0-experimental-b546603b-20260121"; diff --git a/packages/next/src/compiled/react-experimental/cjs/react.react-server.development.js b/packages/next/src/compiled/react-experimental/cjs/react.react-server.development.js index 29dfae61ed2b91..03706d0b977858 100644 --- a/packages/next/src/compiled/react-experimental/cjs/react.react-server.development.js +++ b/packages/next/src/compiled/react-experimental/cjs/react.react-server.development.js @@ -1061,5 +1061,5 @@ exports.useMemo = function (create, deps) { return resolveDispatcher().useMemo(create, deps); }; - exports.version = "19.3.0-experimental-d2908752-20260119"; + exports.version = "19.3.0-experimental-b546603b-20260121"; })(); diff --git a/packages/next/src/compiled/react-experimental/cjs/react.react-server.production.js b/packages/next/src/compiled/react-experimental/cjs/react.react-server.production.js index f8b3779f018913..c5f72a2b53e64f 100644 --- a/packages/next/src/compiled/react-experimental/cjs/react.react-server.production.js +++ b/packages/next/src/compiled/react-experimental/cjs/react.react-server.production.js @@ -579,4 +579,4 @@ exports.useId = function () { exports.useMemo = function (create, deps) { return ReactSharedInternals.H.useMemo(create, deps); }; -exports.version = "19.3.0-experimental-d2908752-20260119"; +exports.version = "19.3.0-experimental-b546603b-20260121"; diff --git a/packages/next/src/compiled/react-is/package.json b/packages/next/src/compiled/react-is/package.json index e61027b59d10b5..4407c718fbb51c 100644 --- a/packages/next/src/compiled/react-is/package.json +++ b/packages/next/src/compiled/react-is/package.json @@ -1,6 +1,6 @@ { "name": "react-is", - "version": "19.3.0-canary-d2908752-20260119", + "version": "19.3.0-canary-b546603b-20260121", "description": "Brand checking of React Elements.", "main": "index.js", "sideEffects": false, diff --git a/packages/next/src/compiled/react-server-dom-turbopack-experimental/cjs/react-server-dom-turbopack-client.browser.development.js b/packages/next/src/compiled/react-server-dom-turbopack-experimental/cjs/react-server-dom-turbopack-client.browser.development.js index 232afd2f66dd6a..ae555281bbc076 100644 --- a/packages/next/src/compiled/react-server-dom-turbopack-experimental/cjs/react-server-dom-turbopack-client.browser.development.js +++ b/packages/next/src/compiled/react-server-dom-turbopack-experimental/cjs/react-server-dom-turbopack-client.browser.development.js @@ -5000,10 +5000,10 @@ return hook.checkDCE ? !0 : !1; })({ bundleType: 1, - version: "19.3.0-experimental-d2908752-20260119", + version: "19.3.0-experimental-b546603b-20260121", rendererPackageName: "react-server-dom-turbopack", currentDispatcherRef: ReactSharedInternals, - reconcilerVersion: "19.3.0-experimental-d2908752-20260119", + reconcilerVersion: "19.3.0-experimental-b546603b-20260121", getCurrentComponentInfo: function () { return currentOwnerInDEV; } diff --git a/packages/next/src/compiled/react-server-dom-turbopack-experimental/package.json b/packages/next/src/compiled/react-server-dom-turbopack-experimental/package.json index 560f452a369efc..616d7c7e396e8d 100644 --- a/packages/next/src/compiled/react-server-dom-turbopack-experimental/package.json +++ b/packages/next/src/compiled/react-server-dom-turbopack-experimental/package.json @@ -48,7 +48,7 @@ "neo-async": "^2.6.1" }, "peerDependencies": { - "react": "0.0.0-experimental-d2908752-20260119", - "react-dom": "0.0.0-experimental-d2908752-20260119" + "react": "0.0.0-experimental-b546603b-20260121", + "react-dom": "0.0.0-experimental-b546603b-20260121" } } \ No newline at end of file diff --git a/packages/next/src/compiled/react-server-dom-turbopack/cjs/react-server-dom-turbopack-client.browser.development.js b/packages/next/src/compiled/react-server-dom-turbopack/cjs/react-server-dom-turbopack-client.browser.development.js index 8f757dd354596a..b214883d093ac0 100644 --- a/packages/next/src/compiled/react-server-dom-turbopack/cjs/react-server-dom-turbopack-client.browser.development.js +++ b/packages/next/src/compiled/react-server-dom-turbopack/cjs/react-server-dom-turbopack-client.browser.development.js @@ -5000,10 +5000,10 @@ return hook.checkDCE ? !0 : !1; })({ bundleType: 1, - version: "19.3.0-canary-d2908752-20260119", + version: "19.3.0-canary-b546603b-20260121", rendererPackageName: "react-server-dom-turbopack", currentDispatcherRef: ReactSharedInternals, - reconcilerVersion: "19.3.0-canary-d2908752-20260119", + reconcilerVersion: "19.3.0-canary-b546603b-20260121", getCurrentComponentInfo: function () { return currentOwnerInDEV; } diff --git a/packages/next/src/compiled/react-server-dom-turbopack/package.json b/packages/next/src/compiled/react-server-dom-turbopack/package.json index 64e0d8c4fa1769..fb70ed7454c200 100644 --- a/packages/next/src/compiled/react-server-dom-turbopack/package.json +++ b/packages/next/src/compiled/react-server-dom-turbopack/package.json @@ -48,7 +48,7 @@ "neo-async": "^2.6.1" }, "peerDependencies": { - "react": "19.3.0-canary-d2908752-20260119", - "react-dom": "19.3.0-canary-d2908752-20260119" + "react": "19.3.0-canary-b546603b-20260121", + "react-dom": "19.3.0-canary-b546603b-20260121" } } \ No newline at end of file diff --git a/packages/next/src/compiled/react-server-dom-webpack-experimental/cjs/react-server-dom-webpack-client.browser.development.js b/packages/next/src/compiled/react-server-dom-webpack-experimental/cjs/react-server-dom-webpack-client.browser.development.js index 0e64cb23414a20..478ff0daa77a1d 100644 --- a/packages/next/src/compiled/react-server-dom-webpack-experimental/cjs/react-server-dom-webpack-client.browser.development.js +++ b/packages/next/src/compiled/react-server-dom-webpack-experimental/cjs/react-server-dom-webpack-client.browser.development.js @@ -5016,10 +5016,10 @@ return hook.checkDCE ? !0 : !1; })({ bundleType: 1, - version: "19.3.0-experimental-d2908752-20260119", + version: "19.3.0-experimental-b546603b-20260121", rendererPackageName: "react-server-dom-webpack", currentDispatcherRef: ReactSharedInternals, - reconcilerVersion: "19.3.0-experimental-d2908752-20260119", + reconcilerVersion: "19.3.0-experimental-b546603b-20260121", getCurrentComponentInfo: function () { return currentOwnerInDEV; } diff --git a/packages/next/src/compiled/react-server-dom-webpack-experimental/package.json b/packages/next/src/compiled/react-server-dom-webpack-experimental/package.json index 9d1b9569f89ea6..79ac0674350fb8 100644 --- a/packages/next/src/compiled/react-server-dom-webpack-experimental/package.json +++ b/packages/next/src/compiled/react-server-dom-webpack-experimental/package.json @@ -52,8 +52,8 @@ "webpack-sources": "^3.2.0" }, "peerDependencies": { - "react": "0.0.0-experimental-d2908752-20260119", - "react-dom": "0.0.0-experimental-d2908752-20260119", + "react": "0.0.0-experimental-b546603b-20260121", + "react-dom": "0.0.0-experimental-b546603b-20260121", "webpack": "^5.59.0" } } \ No newline at end of file diff --git a/packages/next/src/compiled/react-server-dom-webpack/cjs/react-server-dom-webpack-client.browser.development.js b/packages/next/src/compiled/react-server-dom-webpack/cjs/react-server-dom-webpack-client.browser.development.js index b5a5c83b0abc84..2c350014050f1c 100644 --- a/packages/next/src/compiled/react-server-dom-webpack/cjs/react-server-dom-webpack-client.browser.development.js +++ b/packages/next/src/compiled/react-server-dom-webpack/cjs/react-server-dom-webpack-client.browser.development.js @@ -5016,10 +5016,10 @@ return hook.checkDCE ? !0 : !1; })({ bundleType: 1, - version: "19.3.0-canary-d2908752-20260119", + version: "19.3.0-canary-b546603b-20260121", rendererPackageName: "react-server-dom-webpack", currentDispatcherRef: ReactSharedInternals, - reconcilerVersion: "19.3.0-canary-d2908752-20260119", + reconcilerVersion: "19.3.0-canary-b546603b-20260121", getCurrentComponentInfo: function () { return currentOwnerInDEV; } diff --git a/packages/next/src/compiled/react-server-dom-webpack/package.json b/packages/next/src/compiled/react-server-dom-webpack/package.json index 82c87421d54ccb..09f68a22973aed 100644 --- a/packages/next/src/compiled/react-server-dom-webpack/package.json +++ b/packages/next/src/compiled/react-server-dom-webpack/package.json @@ -52,8 +52,8 @@ "webpack-sources": "^3.2.0" }, "peerDependencies": { - "react": "19.3.0-canary-d2908752-20260119", - "react-dom": "19.3.0-canary-d2908752-20260119", + "react": "19.3.0-canary-b546603b-20260121", + "react-dom": "19.3.0-canary-b546603b-20260121", "webpack": "^5.59.0" } } \ No newline at end of file diff --git a/packages/next/src/compiled/react/cjs/react.development.js b/packages/next/src/compiled/react/cjs/react.development.js index 6c58d6193e96d6..e3505759a5e0c5 100644 --- a/packages/next/src/compiled/react/cjs/react.development.js +++ b/packages/next/src/compiled/react/cjs/react.development.js @@ -1322,7 +1322,7 @@ exports.useTransition = function () { return resolveDispatcher().useTransition(); }; - exports.version = "19.3.0-canary-d2908752-20260119"; + exports.version = "19.3.0-canary-b546603b-20260121"; "undefined" !== typeof __REACT_DEVTOOLS_GLOBAL_HOOK__ && "function" === typeof __REACT_DEVTOOLS_GLOBAL_HOOK__.registerInternalModuleStop && diff --git a/packages/next/src/compiled/react/cjs/react.production.js b/packages/next/src/compiled/react/cjs/react.production.js index a0c6d85dcc7785..6ef61a0e20ad8b 100644 --- a/packages/next/src/compiled/react/cjs/react.production.js +++ b/packages/next/src/compiled/react/cjs/react.production.js @@ -562,4 +562,4 @@ exports.useSyncExternalStore = function ( exports.useTransition = function () { return ReactSharedInternals.H.useTransition(); }; -exports.version = "19.3.0-canary-d2908752-20260119"; +exports.version = "19.3.0-canary-b546603b-20260121"; diff --git a/packages/next/src/compiled/react/cjs/react.react-server.development.js b/packages/next/src/compiled/react/cjs/react.react-server.development.js index 83e9a668f614b6..ed8dacae0621b1 100644 --- a/packages/next/src/compiled/react/cjs/react.react-server.development.js +++ b/packages/next/src/compiled/react/cjs/react.react-server.development.js @@ -874,5 +874,5 @@ exports.useMemo = function (create, deps) { return resolveDispatcher().useMemo(create, deps); }; - exports.version = "19.3.0-canary-d2908752-20260119"; + exports.version = "19.3.0-canary-b546603b-20260121"; })(); diff --git a/packages/next/src/compiled/react/cjs/react.react-server.production.js b/packages/next/src/compiled/react/cjs/react.react-server.production.js index 5f78792270b886..93de2d7c2b4044 100644 --- a/packages/next/src/compiled/react/cjs/react.react-server.production.js +++ b/packages/next/src/compiled/react/cjs/react.react-server.production.js @@ -433,4 +433,4 @@ exports.useId = function () { exports.useMemo = function (create, deps) { return ReactSharedInternals.H.useMemo(create, deps); }; -exports.version = "19.3.0-canary-d2908752-20260119"; +exports.version = "19.3.0-canary-b546603b-20260121"; diff --git a/packages/next/src/compiled/unistore/unistore.js b/packages/next/src/compiled/unistore/unistore.js index 1d32d699d186ae..4adb8d57533be8 100644 --- a/packages/next/src/compiled/unistore/unistore.js +++ b/packages/next/src/compiled/unistore/unistore.js @@ -1 +1 @@ -(()=>{var t={333:t=>{function n(t,i){for(var _ in i)t[_]=i[_];return t}t.exports=function(t){var i=[];function u(t){for(var _=[],a=0;a{var t={774:t=>{function n(t,i){for(var _ in i)t[_]=i[_];return t}t.exports=function(t){var i=[];function u(t){for(var _=[],a=0;a=9.0.0' @@ -1085,7 +1085,7 @@ importers: packages/next: dependencies: '@next/env': - specifier: 16.2.0-canary.0 + specifier: 16.2.0-canary.1 version: link:../next-env '@swc/helpers': specifier: 0.5.15 @@ -1100,17 +1100,17 @@ importers: specifier: 8.4.31 version: 8.4.31 react: - specifier: 19.3.0-canary-d2908752-20260119 - version: 19.3.0-canary-d2908752-20260119 + specifier: 19.3.0-canary-b546603b-20260121 + version: 19.3.0-canary-b546603b-20260121 react-dom: - specifier: 19.3.0-canary-d2908752-20260119 - version: 19.3.0-canary-d2908752-20260119(react@19.3.0-canary-d2908752-20260119) + specifier: 19.3.0-canary-b546603b-20260121 + version: 19.3.0-canary-b546603b-20260121(react@19.3.0-canary-b546603b-20260121) sass: specifier: ^1.3.0 version: 1.77.8 styled-jsx: specifier: 5.1.6 - version: 5.1.6(@babel/core@7.26.10)(babel-plugin-macros@3.1.0)(react@19.3.0-canary-d2908752-20260119) + version: 5.1.6(@babel/core@7.26.10)(babel-plugin-macros@3.1.0)(react@19.3.0-canary-b546603b-20260121) optionalDependencies: sharp: specifier: ^0.34.5 @@ -1181,7 +1181,7 @@ importers: version: 7.27.0 '@base-ui-components/react': specifier: 1.0.0-beta.2 - version: 1.0.0-beta.2(@types/react@19.2.2)(react-dom@19.3.0-canary-d2908752-20260119(react@19.3.0-canary-d2908752-20260119))(react@19.3.0-canary-d2908752-20260119) + version: 1.0.0-beta.2(@types/react@19.2.2)(react-dom@19.3.0-canary-b546603b-20260121(react@19.3.0-canary-b546603b-20260121))(react@19.3.0-canary-b546603b-20260121) '@capsizecss/metrics': specifier: 3.4.0 version: 3.4.0 @@ -1213,19 +1213,19 @@ importers: specifier: 1.2.0 version: 1.2.0 '@next/font': - specifier: 16.2.0-canary.0 + specifier: 16.2.0-canary.1 version: link:../font '@next/polyfill-module': - specifier: 16.2.0-canary.0 + specifier: 16.2.0-canary.1 version: link:../next-polyfill-module '@next/polyfill-nomodule': - specifier: 16.2.0-canary.0 + specifier: 16.2.0-canary.1 version: link:../next-polyfill-nomodule '@next/react-refresh-utils': - specifier: 16.2.0-canary.0 + specifier: 16.2.0-canary.1 version: link:../react-refresh-utils '@next/swc': - specifier: 16.2.0-canary.0 + specifier: 16.2.0-canary.1 version: link:../next-swc '@opentelemetry/api': specifier: 1.6.0 @@ -1250,13 +1250,13 @@ importers: version: 3.0.0(@swc/helpers@0.5.15)(webpack@5.98.0(@swc/core@1.11.24(@swc/helpers@0.5.15))(esbuild@0.25.9)) '@storybook/blocks': specifier: 8.6.0 - version: 8.6.0(react-dom@19.3.0-canary-d2908752-20260119(react@19.3.0-canary-d2908752-20260119))(react@19.3.0-canary-d2908752-20260119)(storybook@8.6.0(prettier@3.6.2)) + version: 8.6.0(react-dom@19.3.0-canary-b546603b-20260121(react@19.3.0-canary-b546603b-20260121))(react@19.3.0-canary-b546603b-20260121)(storybook@8.6.0(prettier@3.6.2)) '@storybook/react': specifier: 8.6.0 - version: 8.6.0(@storybook/test@8.6.0(storybook@8.6.0(prettier@3.6.2)))(react-dom@19.3.0-canary-d2908752-20260119(react@19.3.0-canary-d2908752-20260119))(react@19.3.0-canary-d2908752-20260119)(storybook@8.6.0(prettier@3.6.2))(typescript@5.9.2) + version: 8.6.0(@storybook/test@8.6.0(storybook@8.6.0(prettier@3.6.2)))(react-dom@19.3.0-canary-b546603b-20260121(react@19.3.0-canary-b546603b-20260121))(react@19.3.0-canary-b546603b-20260121)(storybook@8.6.0(prettier@3.6.2))(typescript@5.9.2) '@storybook/react-webpack5': specifier: 8.6.0 - version: 8.6.0(@rspack/core@1.6.7(@swc/helpers@0.5.15))(@storybook/test@8.6.0(storybook@8.6.0(prettier@3.6.2)))(@swc/core@1.11.24(@swc/helpers@0.5.15))(esbuild@0.25.9)(react-dom@19.3.0-canary-d2908752-20260119(react@19.3.0-canary-d2908752-20260119))(react@19.3.0-canary-d2908752-20260119)(storybook@8.6.0(prettier@3.6.2))(typescript@5.9.2) + version: 8.6.0(@rspack/core@1.6.7(@swc/helpers@0.5.15))(@storybook/test@8.6.0(storybook@8.6.0(prettier@3.6.2)))(@swc/core@1.11.24(@swc/helpers@0.5.15))(esbuild@0.25.9)(react-dom@19.3.0-canary-b546603b-20260121(react@19.3.0-canary-b546603b-20260121))(react@19.3.0-canary-b546603b-20260121)(storybook@8.6.0(prettier@3.6.2))(typescript@5.9.2) '@storybook/test': specifier: 8.6.0 version: 8.6.0(storybook@8.6.0(prettier@3.6.2)) @@ -1754,7 +1754,7 @@ importers: version: 1.0.35 unistore: specifier: 3.4.1 - version: 3.4.1(react@19.3.0-canary-d2908752-20260119) + version: 3.4.1(react@19.3.0-canary-b546603b-20260121) util: specifier: 0.12.4 version: 0.12.4 @@ -1936,14 +1936,14 @@ importers: packages/third-parties: dependencies: react: - specifier: 19.3.0-canary-d2908752-20260119 - version: 19.3.0-canary-d2908752-20260119 + specifier: 19.3.0-canary-b546603b-20260121 + version: 19.3.0-canary-b546603b-20260121 third-party-capital: specifier: 1.0.20 version: 1.0.20 devDependencies: next: - specifier: 16.2.0-canary.0 + specifier: 16.2.0-canary.1 version: link:../next outdent: specifier: 0.8.0 @@ -2000,14 +2000,14 @@ importers: specifier: 29.5.0 version: 29.5.0 react: - specifier: 19.3.0-canary-d2908752-20260119 - version: 19.3.0-canary-d2908752-20260119 + specifier: 19.3.0-canary-b546603b-20260121 + version: 19.3.0-canary-b546603b-20260121 react-test-renderer: specifier: 18.2.0 - version: 18.2.0(react@19.3.0-canary-d2908752-20260119) + version: 18.2.0(react@19.3.0-canary-b546603b-20260121) styled-jsx: specifier: ^5.1.2 - version: 5.1.6(@babel/core@7.26.10)(babel-plugin-macros@3.1.0)(react@19.3.0-canary-d2908752-20260119) + version: 5.1.6(@babel/core@7.26.10)(babel-plugin-macros@3.1.0)(react@19.3.0-canary-b546603b-20260121) turbopack/packages/devlow-bench: dependencies: @@ -2895,8 +2895,8 @@ packages: engines: {node: '>=14.0.0'} peerDependencies: '@types/react': 19.2.2 - react: 19.3.0-canary-d2908752-20260119 - react-dom: 19.3.0-canary-d2908752-20260119 + react: 19.3.0-canary-b546603b-20260121 + react-dom: 19.3.0-canary-b546603b-20260121 peerDependenciesMeta: '@types/react': optional: true @@ -2905,8 +2905,8 @@ packages: resolution: {integrity: sha512-9+uaWyF1o/PgXqHLJnC81IIG0HlV3o9eFCQ5hWZDMx5NHrFk0rrwqEFGQOB8lti/rnbxNPi+kYYw1D4e8xSn/Q==} peerDependencies: '@types/react': 19.2.2 - react: 19.3.0-canary-d2908752-20260119 - react-dom: 19.3.0-canary-d2908752-20260119 + react: 19.3.0-canary-b546603b-20260121 + react-dom: 19.3.0-canary-b546603b-20260121 peerDependenciesMeta: '@types/react': optional: true @@ -3061,7 +3061,7 @@ packages: resolution: {integrity: sha512-5mlW1DquU5HaxjLkfkGN1GA/fvVGdyHURRiX/0FHl2cfIfRxSOfmxEH5YS43edp0OldZrZ+dkBKbngxcNCdZvA==} peerDependencies: '@types/react': '*' - react: 19.3.0-canary-d2908752-20260119 + react: 19.3.0-canary-b546603b-20260121 peerDependenciesMeta: '@types/react': optional: true @@ -3078,7 +3078,7 @@ packages: '@emotion/use-insertion-effect-with-fallbacks@1.0.1': resolution: {integrity: sha512-jT/qyKZ9rzLErtrjGgdkMBn2OP8wl0G3sQlBb3YPryvKHsjvINUhVaPFfP+fpBcOkmrVOVEEHQFJ7nbj2TH2gw==} peerDependencies: - react: 19.3.0-canary-d2908752-20260119 + react: 19.3.0-canary-b546603b-20260121 '@emotion/utils@1.2.1': resolution: {integrity: sha512-Y2tGf3I+XVnajdItskUCn6LX+VUDmP6lTL4fcqsXAv43dnlbZiuW4MWQW38rW/BVWSE7Q/7+XQocmpnRYILUmg==} @@ -3583,20 +3583,20 @@ packages: '@floating-ui/react-dom@2.1.0': resolution: {integrity: sha512-lNzj5EQmEKn5FFKc04+zasr09h/uX8RtJRNj5gUXsSQIXHVWTVh+hVAg1vOMCexkX8EgvemMvIFpQfkosnVNyA==} peerDependencies: - react: 19.3.0-canary-d2908752-20260119 - react-dom: 19.3.0-canary-d2908752-20260119 + react: 19.3.0-canary-b546603b-20260121 + react-dom: 19.3.0-canary-b546603b-20260121 '@floating-ui/react-dom@2.1.5': resolution: {integrity: sha512-HDO/1/1oH9fjj4eLgegrlH3dklZpHtUYYFiVwMUwfGvk9jWDRWqkklA2/NFScknrcNSspbV868WjXORvreDX+Q==} peerDependencies: - react: 19.3.0-canary-d2908752-20260119 - react-dom: 19.3.0-canary-d2908752-20260119 + react: 19.3.0-canary-b546603b-20260121 + react-dom: 19.3.0-canary-b546603b-20260121 '@floating-ui/react@0.26.16': resolution: {integrity: sha512-HEf43zxZNAI/E781QIVpYSF3K2VH4TTYZpqecjdsFkjsaU1EbaWcM++kw0HXFffj7gDUcBFevX8s0rQGQpxkow==} peerDependencies: - react: 19.3.0-canary-d2908752-20260119 - react-dom: 19.3.0-canary-d2908752-20260119 + react: 19.3.0-canary-b546603b-20260121 + react-dom: 19.3.0-canary-b546603b-20260121 '@floating-ui/utils@0.2.10': resolution: {integrity: sha512-aGTxbpbg8/b5JfU1HXSrbH3wXZuLPJcNEcZQFMxLs3oSzgtVu6nFPkbbGGUvBcUjKV2YyB9Wxxabo+HEH9tcRQ==} @@ -4313,13 +4313,13 @@ packages: resolution: {integrity: sha512-l9ypojKN3PjwO1CSLIsqxi7mA25+7w+xc71Q+JuCCREI0tuGwkZsKbIOpuTATIJOjPh8ycLiW7QxX1LYsRTq6w==} peerDependencies: '@mantine/hooks': 7.10.1 - react: 19.3.0-canary-d2908752-20260119 - react-dom: 19.3.0-canary-d2908752-20260119 + react: 19.3.0-canary-b546603b-20260121 + react-dom: 19.3.0-canary-b546603b-20260121 '@mantine/hooks@7.11.2': resolution: {integrity: sha512-jhyVe/sbDEG2U8rr2lMecUPgQxcfr5hh9HazqGfkS7ZRIMDO7uJ947yAcTMGGkp5Lxtt5TBFt1Cb6tiB2/1agg==} peerDependencies: - react: 19.3.0-canary-d2908752-20260119 + react: 19.3.0-canary-b546603b-20260121 '@mapbox/node-pre-gyp@1.0.5': resolution: {integrity: sha512-4srsKPXWlIxp5Vbqz5uLfBN+du2fJChBoYn/f2h991WLdk7jUvcSk/McVLSv/X+xQIPI8eGD5GjrnygdyHnhPA==} @@ -4339,13 +4339,13 @@ packages: '@mdx-js/react@2.2.1': resolution: {integrity: sha512-YdXcMcEnqZhzql98RNrqYo9cEhTTesBiCclEtoiQUbJwx87q9453GTapYU6kJ8ZZ2ek1Vp25SiAXEFy5O/eAPw==} peerDependencies: - react: 19.3.0-canary-d2908752-20260119 + react: 19.3.0-canary-b546603b-20260121 '@mdx-js/react@3.1.0': resolution: {integrity: sha512-QjHtSaoameoalGnKDT3FoIl4+9RwyTmo9ZJGBdLOks/YOiWHoRDI3PUwEzOE7kEmGcV3AFcp9K6dYu9rEuKLAQ==} peerDependencies: '@types/react': 19.2.2 - react: 19.3.0-canary-d2908752-20260119 + react: 19.3.0-canary-b546603b-20260121 '@modelcontextprotocol/sdk@1.18.1': resolution: {integrity: sha512-d//GE8/Yh7aC3e7p+kZG8JqqEAwwDUmAfvH1quogtbk+ksS6E0RR6toKKESPYYZVre0meqkJb27zb+dhqE9Sgw==} @@ -5016,8 +5016,8 @@ packages: peerDependencies: '@types/react': 19.2.2 '@types/react-dom': 19.2.1 - react: 19.3.0-canary-d2908752-20260119 - react-dom: 19.3.0-canary-d2908752-20260119 + react: 19.3.0-canary-b546603b-20260121 + react-dom: 19.3.0-canary-b546603b-20260121 peerDependenciesMeta: '@types/react': optional: true @@ -5029,8 +5029,8 @@ packages: peerDependencies: '@types/react': 19.2.2 '@types/react-dom': 19.2.1 - react: 19.3.0-canary-d2908752-20260119 - react-dom: 19.3.0-canary-d2908752-20260119 + react: 19.3.0-canary-b546603b-20260121 + react-dom: 19.3.0-canary-b546603b-20260121 peerDependenciesMeta: '@types/react': optional: true @@ -5042,8 +5042,8 @@ packages: peerDependencies: '@types/react': 19.2.2 '@types/react-dom': 19.2.1 - react: 19.3.0-canary-d2908752-20260119 - react-dom: 19.3.0-canary-d2908752-20260119 + react: 19.3.0-canary-b546603b-20260121 + react-dom: 19.3.0-canary-b546603b-20260121 peerDependenciesMeta: '@types/react': optional: true @@ -5055,8 +5055,8 @@ packages: peerDependencies: '@types/react': 19.2.2 '@types/react-dom': 19.2.1 - react: 19.3.0-canary-d2908752-20260119 - react-dom: 19.3.0-canary-d2908752-20260119 + react: 19.3.0-canary-b546603b-20260121 + react-dom: 19.3.0-canary-b546603b-20260121 peerDependenciesMeta: '@types/react': optional: true @@ -5068,8 +5068,8 @@ packages: peerDependencies: '@types/react': 19.2.2 '@types/react-dom': 19.2.1 - react: 19.3.0-canary-d2908752-20260119 - react-dom: 19.3.0-canary-d2908752-20260119 + react: 19.3.0-canary-b546603b-20260121 + react-dom: 19.3.0-canary-b546603b-20260121 peerDependenciesMeta: '@types/react': optional: true @@ -5081,8 +5081,8 @@ packages: peerDependencies: '@types/react': 19.2.2 '@types/react-dom': 19.2.1 - react: 19.3.0-canary-d2908752-20260119 - react-dom: 19.3.0-canary-d2908752-20260119 + react: 19.3.0-canary-b546603b-20260121 + react-dom: 19.3.0-canary-b546603b-20260121 peerDependenciesMeta: '@types/react': optional: true @@ -5094,8 +5094,8 @@ packages: peerDependencies: '@types/react': 19.2.2 '@types/react-dom': 19.2.1 - react: 19.3.0-canary-d2908752-20260119 - react-dom: 19.3.0-canary-d2908752-20260119 + react: 19.3.0-canary-b546603b-20260121 + react-dom: 19.3.0-canary-b546603b-20260121 peerDependenciesMeta: '@types/react': optional: true @@ -5106,7 +5106,7 @@ packages: resolution: {integrity: sha512-b4inOtiaOnYf9KWyO3jAeeCG6FeyfY6ldiEPanbUjWd+xIk5wZeHa8yVwmrJ2vderhu/BQvzCrJI0lHd+wIiqw==} peerDependencies: '@types/react': 19.2.2 - react: 19.3.0-canary-d2908752-20260119 + react: 19.3.0-canary-b546603b-20260121 peerDependenciesMeta: '@types/react': optional: true @@ -5115,7 +5115,7 @@ packages: resolution: {integrity: sha512-Y9VzoRDSJtgFMUCoiZBDVo084VQ5hfpXxVE+NgkdNsjiDBByiImMZKKhxMwCbdHvhlENG6a833CbFkOQvTricw==} peerDependencies: '@types/react': 19.2.2 - react: 19.3.0-canary-d2908752-20260119 + react: 19.3.0-canary-b546603b-20260121 peerDependenciesMeta: '@types/react': optional: true @@ -5124,7 +5124,7 @@ packages: resolution: {integrity: sha512-z4eqJvfiNnFMHIIvXP3CY57y2WJs5g2v3X0zm9mEJkrkNv4rDxu+sg9Jh8EkXyeqBkB7SOcboo9dMVqhyrACIg==} peerDependencies: '@types/react': 19.2.2 - react: 19.3.0-canary-d2908752-20260119 + react: 19.3.0-canary-b546603b-20260121 peerDependenciesMeta: '@types/react': optional: true @@ -5133,7 +5133,7 @@ packages: resolution: {integrity: sha512-OKrckBy+sMEgYM/sMmqmErVn0kZqrHPJze+Ql3DzYsDDp0hl0L62nx/2122/Bvps1qz645jlcu2tD9lrRSdf8A==} peerDependencies: '@types/react': 19.2.2 - react: 19.3.0-canary-d2908752-20260119 + react: 19.3.0-canary-b546603b-20260121 peerDependenciesMeta: '@types/react': optional: true @@ -5142,7 +5142,7 @@ packages: resolution: {integrity: sha512-UASk9zi+crv9WteK/NU4PLvOoL3OuE6BWVKNF6hPRBtYBDXQ2u5iu3O59zUlJiTVvkyuycnqrztsHVJwcK9K+Q==} peerDependencies: '@types/react': 19.2.2 - react: 19.3.0-canary-d2908752-20260119 + react: 19.3.0-canary-b546603b-20260121 peerDependenciesMeta: '@types/react': optional: true @@ -5151,7 +5151,7 @@ packages: resolution: {integrity: sha512-jCi/QKUM2r1Ju5a3J64TH2A5SpKAgh0LpknyqdQ4m6DCV0xJ2HG1xARRwNGPQfi1SLdLWZ1OJz6F4OMBBNiGJA==} peerDependencies: '@types/react': 19.2.2 - react: 19.3.0-canary-d2908752-20260119 + react: 19.3.0-canary-b546603b-20260121 peerDependenciesMeta: '@types/react': optional: true @@ -5161,8 +5161,8 @@ packages: peerDependencies: '@types/react': 19.2.2 '@types/react-dom': 19.2.1 - react: 19.3.0-canary-d2908752-20260119 - react-dom: 19.3.0-canary-d2908752-20260119 + react: 19.3.0-canary-b546603b-20260121 + react-dom: 19.3.0-canary-b546603b-20260121 peerDependenciesMeta: '@types/react': optional: true @@ -5174,8 +5174,8 @@ packages: peerDependencies: '@types/react': 19.2.2 '@types/react-dom': 19.2.1 - react: 19.3.0-canary-d2908752-20260119 - react-dom: 19.3.0-canary-d2908752-20260119 + react: 19.3.0-canary-b546603b-20260121 + react-dom: 19.3.0-canary-b546603b-20260121 peerDependenciesMeta: '@types/react': optional: true @@ -5186,7 +5186,7 @@ packages: resolution: {integrity: sha512-BUuBvgThEiAXh2DWu93XsT+a3aWrGqolGlqqw5VU1kG7p/ZH2cuDlM1sRLNnY3QcBS69UIz2mcKhMxDsdewhjg==} peerDependencies: '@types/react': 19.2.2 - react: 19.3.0-canary-d2908752-20260119 + react: 19.3.0-canary-b546603b-20260121 peerDependenciesMeta: '@types/react': optional: true @@ -5195,7 +5195,7 @@ packages: resolution: {integrity: sha512-1UEWRX6jnOA2y4H5WczZ44gOOjTEmlqv1uNW4GAJEO5+bauCBhv8snY65Iw5/VOS/ghKN9gr2KjnLKxrsvoMVw==} peerDependencies: '@types/react': 19.2.2 - react: 19.3.0-canary-d2908752-20260119 + react: 19.3.0-canary-b546603b-20260121 peerDependenciesMeta: '@types/react': optional: true @@ -5205,8 +5205,8 @@ packages: peerDependencies: '@types/react': 19.2.2 '@types/react-dom': 19.2.1 - react: 19.3.0-canary-d2908752-20260119 - react-dom: 19.3.0-canary-d2908752-20260119 + react: 19.3.0-canary-b546603b-20260121 + react-dom: 19.3.0-canary-b546603b-20260121 peerDependenciesMeta: '@types/react': optional: true @@ -5218,8 +5218,8 @@ packages: peerDependencies: '@types/react': 19.2.2 '@types/react-dom': 19.2.1 - react: 19.3.0-canary-d2908752-20260119 - react-dom: 19.3.0-canary-d2908752-20260119 + react: 19.3.0-canary-b546603b-20260121 + react-dom: 19.3.0-canary-b546603b-20260121 peerDependenciesMeta: '@types/react': optional: true @@ -5231,8 +5231,8 @@ packages: peerDependencies: '@types/react': 19.2.2 '@types/react-dom': 19.2.1 - react: 19.3.0-canary-d2908752-20260119 - react-dom: 19.3.0-canary-d2908752-20260119 + react: 19.3.0-canary-b546603b-20260121 + react-dom: 19.3.0-canary-b546603b-20260121 peerDependenciesMeta: '@types/react': optional: true @@ -5243,7 +5243,7 @@ packages: resolution: {integrity: sha512-pSIwfrT1a6sIoDASCSpFwOasEwKTZWDw/iBdtnqKO7v6FeOzYJ7U53cPzYFVR3geGGXgVHaH+CdngrrAzqUGxg==} peerDependencies: '@types/react': 19.2.2 - react: 19.3.0-canary-d2908752-20260119 + react: 19.3.0-canary-b546603b-20260121 peerDependenciesMeta: '@types/react': optional: true @@ -5252,7 +5252,7 @@ packages: resolution: {integrity: sha512-0rFg/Rj2Q62NCm62jZw0QX7a3sz6QCQU0LpZdNrJX8byRGaGVTqbrW9jAoIAHyMQqsNpeZ81YgSizOt5WXq0Pw==} peerDependencies: '@types/react': 19.2.2 - react: 19.3.0-canary-d2908752-20260119 + react: 19.3.0-canary-b546603b-20260121 peerDependenciesMeta: '@types/react': optional: true @@ -5262,8 +5262,8 @@ packages: peerDependencies: '@types/react': 19.2.2 '@types/react-dom': 19.2.1 - react: 19.3.0-canary-d2908752-20260119 - react-dom: 19.3.0-canary-d2908752-20260119 + react: 19.3.0-canary-b546603b-20260121 + react-dom: 19.3.0-canary-b546603b-20260121 peerDependenciesMeta: '@types/react': optional: true @@ -5275,8 +5275,8 @@ packages: peerDependencies: '@types/react': 19.2.2 '@types/react-dom': 19.2.1 - react: 19.3.0-canary-d2908752-20260119 - react-dom: 19.3.0-canary-d2908752-20260119 + react: 19.3.0-canary-b546603b-20260121 + react-dom: 19.3.0-canary-b546603b-20260121 peerDependenciesMeta: '@types/react': optional: true @@ -5287,7 +5287,7 @@ packages: resolution: {integrity: sha512-EJUrI8yYh7WOjNOqpoJaf1jlFIH2LvtgAl+YcFqNCa+4hj64ZXmPkAKOFs/ukjz3byN6bdb/AVUqHkI8/uWWMA==} peerDependencies: '@types/react': 19.2.2 - react: 19.3.0-canary-d2908752-20260119 + react: 19.3.0-canary-b546603b-20260121 peerDependenciesMeta: '@types/react': optional: true @@ -5296,7 +5296,7 @@ packages: resolution: {integrity: sha512-kGkGegYIdQsOb4XjsfM97rXsiHaBwco+hFI66oO4s9LU+PLAC5oJ7khdOVFxkhsmlbpUqDAvXw11CluXP+jkHg==} peerDependencies: '@types/react': 19.2.2 - react: 19.3.0-canary-d2908752-20260119 + react: 19.3.0-canary-b546603b-20260121 peerDependenciesMeta: '@types/react': optional: true @@ -5306,8 +5306,8 @@ packages: peerDependencies: '@types/react': 19.2.2 '@types/react-dom': 19.2.1 - react: 19.3.0-canary-d2908752-20260119 - react-dom: 19.3.0-canary-d2908752-20260119 + react: 19.3.0-canary-b546603b-20260121 + react-dom: 19.3.0-canary-b546603b-20260121 peerDependenciesMeta: '@types/react': optional: true @@ -5319,8 +5319,8 @@ packages: peerDependencies: '@types/react': 19.2.2 '@types/react-dom': 19.2.1 - react: 19.3.0-canary-d2908752-20260119 - react-dom: 19.3.0-canary-d2908752-20260119 + react: 19.3.0-canary-b546603b-20260121 + react-dom: 19.3.0-canary-b546603b-20260121 peerDependenciesMeta: '@types/react': optional: true @@ -5332,8 +5332,8 @@ packages: peerDependencies: '@types/react': 19.2.2 '@types/react-dom': 19.2.1 - react: 19.3.0-canary-d2908752-20260119 - react-dom: 19.3.0-canary-d2908752-20260119 + react: 19.3.0-canary-b546603b-20260121 + react-dom: 19.3.0-canary-b546603b-20260121 peerDependenciesMeta: '@types/react': optional: true @@ -5345,8 +5345,8 @@ packages: peerDependencies: '@types/react': 19.2.2 '@types/react-dom': 19.2.1 - react: 19.3.0-canary-d2908752-20260119 - react-dom: 19.3.0-canary-d2908752-20260119 + react: 19.3.0-canary-b546603b-20260121 + react-dom: 19.3.0-canary-b546603b-20260121 peerDependenciesMeta: '@types/react': optional: true @@ -5358,8 +5358,8 @@ packages: peerDependencies: '@types/react': 19.2.2 '@types/react-dom': 19.2.1 - react: 19.3.0-canary-d2908752-20260119 - react-dom: 19.3.0-canary-d2908752-20260119 + react: 19.3.0-canary-b546603b-20260121 + react-dom: 19.3.0-canary-b546603b-20260121 peerDependenciesMeta: '@types/react': optional: true @@ -5371,8 +5371,8 @@ packages: peerDependencies: '@types/react': 19.2.2 '@types/react-dom': 19.2.1 - react: 19.3.0-canary-d2908752-20260119 - react-dom: 19.3.0-canary-d2908752-20260119 + react: 19.3.0-canary-b546603b-20260121 + react-dom: 19.3.0-canary-b546603b-20260121 peerDependenciesMeta: '@types/react': optional: true @@ -5384,8 +5384,8 @@ packages: peerDependencies: '@types/react': 19.2.2 '@types/react-dom': 19.2.1 - react: 19.3.0-canary-d2908752-20260119 - react-dom: 19.3.0-canary-d2908752-20260119 + react: 19.3.0-canary-b546603b-20260121 + react-dom: 19.3.0-canary-b546603b-20260121 peerDependenciesMeta: '@types/react': optional: true @@ -5397,8 +5397,8 @@ packages: peerDependencies: '@types/react': 19.2.2 '@types/react-dom': 19.2.1 - react: 19.3.0-canary-d2908752-20260119 - react-dom: 19.3.0-canary-d2908752-20260119 + react: 19.3.0-canary-b546603b-20260121 + react-dom: 19.3.0-canary-b546603b-20260121 peerDependenciesMeta: '@types/react': optional: true @@ -5410,8 +5410,8 @@ packages: peerDependencies: '@types/react': 19.2.2 '@types/react-dom': 19.2.1 - react: 19.3.0-canary-d2908752-20260119 - react-dom: 19.3.0-canary-d2908752-20260119 + react: 19.3.0-canary-b546603b-20260121 + react-dom: 19.3.0-canary-b546603b-20260121 peerDependenciesMeta: '@types/react': optional: true @@ -5423,8 +5423,8 @@ packages: peerDependencies: '@types/react': 19.2.2 '@types/react-dom': 19.2.1 - react: 19.3.0-canary-d2908752-20260119 - react-dom: 19.3.0-canary-d2908752-20260119 + react: 19.3.0-canary-b546603b-20260121 + react-dom: 19.3.0-canary-b546603b-20260121 peerDependenciesMeta: '@types/react': optional: true @@ -5436,8 +5436,8 @@ packages: peerDependencies: '@types/react': 19.2.2 '@types/react-dom': 19.2.1 - react: 19.3.0-canary-d2908752-20260119 - react-dom: 19.3.0-canary-d2908752-20260119 + react: 19.3.0-canary-b546603b-20260121 + react-dom: 19.3.0-canary-b546603b-20260121 peerDependenciesMeta: '@types/react': optional: true @@ -5449,8 +5449,8 @@ packages: peerDependencies: '@types/react': 19.2.2 '@types/react-dom': 19.2.1 - react: 19.3.0-canary-d2908752-20260119 - react-dom: 19.3.0-canary-d2908752-20260119 + react: 19.3.0-canary-b546603b-20260121 + react-dom: 19.3.0-canary-b546603b-20260121 peerDependenciesMeta: '@types/react': optional: true @@ -5462,8 +5462,8 @@ packages: peerDependencies: '@types/react': 19.2.2 '@types/react-dom': 19.2.1 - react: 19.3.0-canary-d2908752-20260119 - react-dom: 19.3.0-canary-d2908752-20260119 + react: 19.3.0-canary-b546603b-20260121 + react-dom: 19.3.0-canary-b546603b-20260121 peerDependenciesMeta: '@types/react': optional: true @@ -5475,8 +5475,8 @@ packages: peerDependencies: '@types/react': 19.2.2 '@types/react-dom': 19.2.1 - react: 19.3.0-canary-d2908752-20260119 - react-dom: 19.3.0-canary-d2908752-20260119 + react: 19.3.0-canary-b546603b-20260121 + react-dom: 19.3.0-canary-b546603b-20260121 peerDependenciesMeta: '@types/react': optional: true @@ -5488,8 +5488,8 @@ packages: peerDependencies: '@types/react': 19.2.2 '@types/react-dom': 19.2.1 - react: 19.3.0-canary-d2908752-20260119 - react-dom: 19.3.0-canary-d2908752-20260119 + react: 19.3.0-canary-b546603b-20260121 + react-dom: 19.3.0-canary-b546603b-20260121 peerDependenciesMeta: '@types/react': optional: true @@ -5501,8 +5501,8 @@ packages: peerDependencies: '@types/react': 19.2.2 '@types/react-dom': 19.2.1 - react: 19.3.0-canary-d2908752-20260119 - react-dom: 19.3.0-canary-d2908752-20260119 + react: 19.3.0-canary-b546603b-20260121 + react-dom: 19.3.0-canary-b546603b-20260121 peerDependenciesMeta: '@types/react': optional: true @@ -5514,8 +5514,8 @@ packages: peerDependencies: '@types/react': 19.2.2 '@types/react-dom': 19.2.1 - react: 19.3.0-canary-d2908752-20260119 - react-dom: 19.3.0-canary-d2908752-20260119 + react: 19.3.0-canary-b546603b-20260121 + react-dom: 19.3.0-canary-b546603b-20260121 peerDependenciesMeta: '@types/react': optional: true @@ -5527,8 +5527,8 @@ packages: peerDependencies: '@types/react': 19.2.2 '@types/react-dom': 19.2.1 - react: 19.3.0-canary-d2908752-20260119 - react-dom: 19.3.0-canary-d2908752-20260119 + react: 19.3.0-canary-b546603b-20260121 + react-dom: 19.3.0-canary-b546603b-20260121 peerDependenciesMeta: '@types/react': optional: true @@ -5540,8 +5540,8 @@ packages: peerDependencies: '@types/react': 19.2.2 '@types/react-dom': 19.2.1 - react: 19.3.0-canary-d2908752-20260119 - react-dom: 19.3.0-canary-d2908752-20260119 + react: 19.3.0-canary-b546603b-20260121 + react-dom: 19.3.0-canary-b546603b-20260121 peerDependenciesMeta: '@types/react': optional: true @@ -5552,7 +5552,7 @@ packages: resolution: {integrity: sha512-FUCf5XMfmW4dtYl69pdS4DbxKy8nj4M7SafBgPllysxmdachynNflAdp/gCsnYWNDnge6tI9onzMp5ARYc1KNw==} peerDependencies: '@types/react': 19.2.2 - react: 19.3.0-canary-d2908752-20260119 + react: 19.3.0-canary-b546603b-20260121 peerDependenciesMeta: '@types/react': optional: true @@ -5561,7 +5561,7 @@ packages: resolution: {integrity: sha512-RApLLOcINYJA+dMVbOju7MYv1Mb2EBp2nH4HdDzXTSyaR5optlm6Otrz1euW3HbdOR8UmmFK06TD+A9frYWv+g==} peerDependencies: '@types/react': 19.2.2 - react: 19.3.0-canary-d2908752-20260119 + react: 19.3.0-canary-b546603b-20260121 peerDependenciesMeta: '@types/react': optional: true @@ -5570,7 +5570,7 @@ packages: resolution: {integrity: sha512-aeNmHnBxbi2St0au6VBVC7JXFlhLlOnvIIlePNniyUNAClzmtAUEY8/pBiK3iHjufOlwA+c20/8jngo7xcrg8A==} peerDependencies: '@types/react': 19.2.2 - react: 19.3.0-canary-d2908752-20260119 + react: 19.3.0-canary-b546603b-20260121 peerDependenciesMeta: '@types/react': optional: true @@ -5580,8 +5580,8 @@ packages: peerDependencies: '@types/react': 19.2.2 '@types/react-dom': 19.2.1 - react: 19.3.0-canary-d2908752-20260119 - react-dom: 19.3.0-canary-d2908752-20260119 + react: 19.3.0-canary-b546603b-20260121 + react-dom: 19.3.0-canary-b546603b-20260121 peerDependenciesMeta: '@types/react': optional: true @@ -5593,8 +5593,8 @@ packages: peerDependencies: '@types/react': 19.2.2 '@types/react-dom': 19.2.1 - react: 19.3.0-canary-d2908752-20260119 - react-dom: 19.3.0-canary-d2908752-20260119 + react: 19.3.0-canary-b546603b-20260121 + react-dom: 19.3.0-canary-b546603b-20260121 peerDependenciesMeta: '@types/react': optional: true @@ -5606,8 +5606,8 @@ packages: peerDependencies: '@types/react': 19.2.2 '@types/react-dom': 19.2.1 - react: 19.3.0-canary-d2908752-20260119 - react-dom: 19.3.0-canary-d2908752-20260119 + react: 19.3.0-canary-b546603b-20260121 + react-dom: 19.3.0-canary-b546603b-20260121 peerDependenciesMeta: '@types/react': optional: true @@ -5619,8 +5619,8 @@ packages: peerDependencies: '@types/react': 19.2.2 '@types/react-dom': 19.2.1 - react: 19.3.0-canary-d2908752-20260119 - react-dom: 19.3.0-canary-d2908752-20260119 + react: 19.3.0-canary-b546603b-20260121 + react-dom: 19.3.0-canary-b546603b-20260121 peerDependenciesMeta: '@types/react': optional: true @@ -5631,7 +5631,7 @@ packages: resolution: {integrity: sha512-CasTfvsy+frcFkbXtSJ2Zu9JHpN8TYKxkgJGWbjiZhFivxaeW7rMeZt7QELGVLaYVfFMsKHjb7Ak0nMEe+2Vfw==} peerDependencies: '@types/react': 19.2.2 - react: 19.3.0-canary-d2908752-20260119 + react: 19.3.0-canary-b546603b-20260121 peerDependenciesMeta: '@types/react': optional: true @@ -5640,7 +5640,7 @@ packages: resolution: {integrity: sha512-FkBMwD+qbGQeMu1cOHnuGB6x4yzPjho8ap5WtbEJ26umhgqVXbhekKUQO+hZEL1vU92a3wHwdp0HAcqAUF5iDg==} peerDependencies: '@types/react': 19.2.2 - react: 19.3.0-canary-d2908752-20260119 + react: 19.3.0-canary-b546603b-20260121 peerDependenciesMeta: '@types/react': optional: true @@ -5649,7 +5649,7 @@ packages: resolution: {integrity: sha512-MtfMVJiSr2NjzS0Aa90NPTnvTSg6C/JLCV7ma0W6+OMV78vd8OyRpID+Ng9LxzsPbLeuBnWBA1Nq30AtBIDChw==} peerDependencies: '@types/react': 19.2.2 - react: 19.3.0-canary-d2908752-20260119 + react: 19.3.0-canary-b546603b-20260121 peerDependenciesMeta: '@types/react': optional: true @@ -5658,7 +5658,7 @@ packages: resolution: {integrity: sha512-BjasUjixPFdS+NKkypcyyN5Pmg83Olst0+c6vGov0diwTEo6mgdqVR6hxcEgFuh4QrAs7Rc+9KuGJ9TVCj0Zzg==} peerDependencies: '@types/react': 19.2.2 - react: 19.3.0-canary-d2908752-20260119 + react: 19.3.0-canary-b546603b-20260121 peerDependenciesMeta: '@types/react': optional: true @@ -5667,7 +5667,7 @@ packages: resolution: {integrity: sha512-Qp8WbZOBe+blgpuUT+lw2xheLP8q0oatc9UpmiemEICxGvFLYmHm9QowVZGHtJlGbS6A6yJ3iViad/2cVjnOiA==} peerDependencies: '@types/react': 19.2.2 - react: 19.3.0-canary-d2908752-20260119 + react: 19.3.0-canary-b546603b-20260121 peerDependenciesMeta: '@types/react': optional: true @@ -5676,7 +5676,7 @@ packages: resolution: {integrity: sha512-L7vwWlR1kTTQ3oh7g1O0CBF3YCyyTj8NmhLR+phShpyA50HCfBFKVJTpshm9PzLiKmehsrQzTYTpX9HvmC9rhw==} peerDependencies: '@types/react': 19.2.2 - react: 19.3.0-canary-d2908752-20260119 + react: 19.3.0-canary-b546603b-20260121 peerDependenciesMeta: '@types/react': optional: true @@ -5685,7 +5685,7 @@ packages: resolution: {integrity: sha512-Il0+boE7w/XebUHyBjroE+DbByORGR9KKmITzbR7MyQ4akpORYP/ZmbhAr0DG7RmmBqoOnZdy2QlvajJ2QA59g==} peerDependencies: '@types/react': 19.2.2 - react: 19.3.0-canary-d2908752-20260119 + react: 19.3.0-canary-b546603b-20260121 peerDependenciesMeta: '@types/react': optional: true @@ -5694,7 +5694,7 @@ packages: resolution: {integrity: sha512-+FPE0rOdziWSrH9athwI1R0HDVbWlEhd+FR+aSDk4uWGmSJ9Z54sdZVDQPZAinJhJXwfT+qnj969mCsT2gfm5w==} peerDependencies: '@types/react': 19.2.2 - react: 19.3.0-canary-d2908752-20260119 + react: 19.3.0-canary-b546603b-20260121 peerDependenciesMeta: '@types/react': optional: true @@ -5703,7 +5703,7 @@ packages: resolution: {integrity: sha512-RbJRS4UWQFkzHTTwVymMTUv8EqYhOp8dOOviLj2ugtTiXRaRQS7GLGxZTLL1jWhMeoSCf5zmcZkqTl9IiYfXcQ==} peerDependencies: '@types/react': 19.2.2 - react: 19.3.0-canary-d2908752-20260119 + react: 19.3.0-canary-b546603b-20260121 peerDependenciesMeta: '@types/react': optional: true @@ -5712,7 +5712,7 @@ packages: resolution: {integrity: sha512-2dHfToCj/pzca2Ck724OZ5L0EVrr3eHRNsG/b3xQJLA2hZpVCS99bLAX+hm1IHXDEnzU6by5z/5MIY794/a8NQ==} peerDependencies: '@types/react': 19.2.2 - react: 19.3.0-canary-d2908752-20260119 + react: 19.3.0-canary-b546603b-20260121 peerDependenciesMeta: '@types/react': optional: true @@ -5721,7 +5721,7 @@ packages: resolution: {integrity: sha512-0Fmkebhr6PiseyZlYAOtLS+nb7jLmpqTrJyv61Pe68MKYW6OWdRE2kI70TaYY27u7H0lajqM3hSMMLFq18Z7nQ==} peerDependencies: '@types/react': 19.2.2 - react: 19.3.0-canary-d2908752-20260119 + react: 19.3.0-canary-b546603b-20260121 peerDependenciesMeta: '@types/react': optional: true @@ -5730,7 +5730,7 @@ packages: resolution: {integrity: sha512-QTYuDesS0VtuHNNvMh+CjlKJ4LJickCMUAqjlE3+j8w+RlRpwyX3apEQKGFzbZGdo7XNG1tXa+bQqIE7HIXT2w==} peerDependencies: '@types/react': 19.2.2 - react: 19.3.0-canary-d2908752-20260119 + react: 19.3.0-canary-b546603b-20260121 peerDependenciesMeta: '@types/react': optional: true @@ -5739,7 +5739,7 @@ packages: resolution: {integrity: sha512-XW3/vWuIXHa+2Uwcc2ABSfcCledmXhhQPlGbfcRXbiUQI5Icjcg19BGCZVKKInYbvUCut/ufbbLLPFC5cbb1hw==} peerDependencies: '@types/react': 19.2.2 - react: 19.3.0-canary-d2908752-20260119 + react: 19.3.0-canary-b546603b-20260121 peerDependenciesMeta: '@types/react': optional: true @@ -5748,7 +5748,7 @@ packages: resolution: {integrity: sha512-ewrXRDTAqAXlkl6t/fkXWNAhFX9I+CkKlw6zjEwk86RSPKwZr3xpBRso655aqYafwtnbpHLj6toFzmd6xdVptQ==} peerDependencies: '@types/react': 19.2.2 - react: 19.3.0-canary-d2908752-20260119 + react: 19.3.0-canary-b546603b-20260121 peerDependenciesMeta: '@types/react': optional: true @@ -5758,8 +5758,8 @@ packages: peerDependencies: '@types/react': 19.2.2 '@types/react-dom': 19.2.1 - react: 19.3.0-canary-d2908752-20260119 - react-dom: 19.3.0-canary-d2908752-20260119 + react: 19.3.0-canary-b546603b-20260121 + react-dom: 19.3.0-canary-b546603b-20260121 peerDependenciesMeta: '@types/react': optional: true @@ -5771,8 +5771,8 @@ packages: peerDependencies: '@types/react': 19.2.2 '@types/react-dom': 19.2.1 - react: 19.3.0-canary-d2908752-20260119 - react-dom: 19.3.0-canary-d2908752-20260119 + react: 19.3.0-canary-b546603b-20260121 + react-dom: 19.3.0-canary-b546603b-20260121 peerDependenciesMeta: '@types/react': optional: true @@ -6076,8 +6076,8 @@ packages: '@storybook/blocks@8.6.0': resolution: {integrity: sha512-3PNxlB5Ooj8CIhttbDxeV6kW7ui+2GEdTngtqhnsUHVjzeTKpilsk2lviOeUzqlyq5FDK+rhpZ3L3DJ9pDvioA==} peerDependencies: - react: 19.3.0-canary-d2908752-20260119 - react-dom: 19.3.0-canary-d2908752-20260119 + react: 19.3.0-canary-b546603b-20260121 + react-dom: 19.3.0-canary-b546603b-20260121 storybook: ^8.6.0 peerDependenciesMeta: react: @@ -6127,8 +6127,8 @@ packages: resolution: {integrity: sha512-Nz/UzeYQdUZUhacrPyfkiiysSjydyjgg/p0P9HxB4p/WaJUUjMAcaoaLgy3EXx61zZJ3iD36WPuDkZs5QYrA0A==} engines: {node: '>=14.0.0'} peerDependencies: - react: 19.3.0-canary-d2908752-20260119 - react-dom: 19.3.0-canary-d2908752-20260119 + react: 19.3.0-canary-b546603b-20260121 + react-dom: 19.3.0-canary-b546603b-20260121 '@storybook/instrumenter@8.6.0': resolution: {integrity: sha512-eEY/Hfa3Vj5Nv4vHRHlSqjoyW6oAKNK3rKIXfL/eawQwb7rKhzijDLG5YBH44Hh7dEPIqUp0LEdgpyIY7GXezg==} @@ -6144,8 +6144,8 @@ packages: resolution: {integrity: sha512-04T86VG0UJtiozgZkTR5sY1qM3E0Rgwqwllvyy7kFFdkV+Sv/VsPjW9sC38s9C8FtCYRL8pJZz81ey3oylpIMA==} engines: {node: '>=18.0.0'} peerDependencies: - react: 19.3.0-canary-d2908752-20260119 - react-dom: 19.3.0-canary-d2908752-20260119 + react: 19.3.0-canary-b546603b-20260121 + react-dom: 19.3.0-canary-b546603b-20260121 storybook: ^8.6.0 typescript: '*' peerDependenciesMeta: @@ -6166,16 +6166,16 @@ packages: '@storybook/react-dom-shim@8.6.0': resolution: {integrity: sha512-5Y+vMHhcx0xnaNsLQMbkmjc3zkDn/fGBNsiLH2e4POvW3ZQvOxjoyxAsEQaKwLtFgsdCFSd2tR89F6ItYrA2JQ==} peerDependencies: - react: 19.3.0-canary-d2908752-20260119 - react-dom: 19.3.0-canary-d2908752-20260119 + react: 19.3.0-canary-b546603b-20260121 + react-dom: 19.3.0-canary-b546603b-20260121 storybook: ^8.6.0 '@storybook/react-webpack5@8.6.0': resolution: {integrity: sha512-2L9CYDPn1OL0B8K5EU/Wpo9Slg8f0vkYPaPioQnmcK3Q4SJR4JAuDVWHUtNdxhaPOkHIy887Tfrf6BEC/blMaQ==} engines: {node: '>=18.0.0'} peerDependencies: - react: 19.3.0-canary-d2908752-20260119 - react-dom: 19.3.0-canary-d2908752-20260119 + react: 19.3.0-canary-b546603b-20260121 + react-dom: 19.3.0-canary-b546603b-20260121 storybook: ^8.6.0 typescript: '>= 4.2.x' peerDependenciesMeta: @@ -6187,8 +6187,8 @@ packages: engines: {node: '>=18.0.0'} peerDependencies: '@storybook/test': 8.6.0 - react: 19.3.0-canary-d2908752-20260119 - react-dom: 19.3.0-canary-d2908752-20260119 + react: 19.3.0-canary-b546603b-20260121 + react-dom: 19.3.0-canary-b546603b-20260121 storybook: ^8.6.0 typescript: '>= 4.2.x' peerDependenciesMeta: @@ -6456,8 +6456,8 @@ packages: engines: {node: '>=18'} peerDependencies: '@types/react': 19.2.2 - react: 19.3.0-canary-d2908752-20260119 - react-dom: 19.3.0-canary-d2908752-20260119 + react: 19.3.0-canary-b546603b-20260121 + react-dom: 19.3.0-canary-b546603b-20260121 peerDependenciesMeta: '@types/react': optional: true @@ -8395,8 +8395,8 @@ packages: cmdk@1.0.4: resolution: {integrity: sha512-AnsjfHyHpQ/EFeAnG216WY7A5LiYCoZzCSygiLvfXC3H3LFGCprErteUcszaVluGOhuOTbJS3jWHrSDYPBBygg==} peerDependencies: - react: 19.3.0-canary-d2908752-20260119 - react-dom: 19.3.0-canary-d2908752-20260119 + react: 19.3.0-canary-b546603b-20260121 + react-dom: 19.3.0-canary-b546603b-20260121 co@4.6.0: resolution: {integrity: sha512-QVb0dM5HvG+uaxitm8wONl7jltx8dqhfU33DcqtOZcLSVIKSDDLDi7+0LbAKiyI8hD9u42m2YxXSkMGWThaecQ==} @@ -10062,8 +10062,8 @@ packages: peerDependencies: eslint: '>=8.0.0' - eslint-plugin-react-hooks@0.0.0-experimental-d2908752-20260119: - resolution: {integrity: sha512-PwIzyQWWst/tTgHObMqd72TBnFFAFkDuHzmcZkORNV1a6AaPIhPnjCfqqx0oIYhudjyYrlW2BdshXsKKS/TmMg==} + eslint-plugin-react-hooks@0.0.0-experimental-b546603b-20260121: + resolution: {integrity: sha512-H3VKOGMsvpcR0RvDplyyMp4UCEu1gX4yjj3iG1vlQndv8qqjeQOJahAvUVyHcqlZZhNgHYVm31yzGPGSWpqxSg==} engines: {node: '>=18'} peerDependencies: eslint: ^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0-0 || ^9.0.0 @@ -10712,8 +10712,8 @@ packages: '@types/react': 19.2.2 algoliasearch: 5.x.x next: 14.x.x || 15.x.x - react: 19.3.0-canary-d2908752-20260119 - react-dom: 19.3.0-canary-d2908752-20260119 + react: 19.3.0-canary-b546603b-20260121 + react-dom: 19.3.0-canary-b546603b-20260121 react-router: 7.x.x waku: ^0.26.0 peerDependenciesMeta: @@ -10745,7 +10745,7 @@ packages: '@fumadocs/mdx-remote': ^1.4.0 fumadocs-core: ^14.0.0 || ^15.0.0 next: ^15.3.0 - react: 19.3.0-canary-d2908752-20260119 + react: 19.3.0-canary-b546603b-20260121 vite: 6.x.x || 7.x.x peerDependenciesMeta: '@fumadocs/mdx-remote': @@ -10762,8 +10762,8 @@ packages: peerDependencies: '@types/react': 19.2.2 next: 14.x.x || 15.x.x - react: 19.3.0-canary-d2908752-20260119 - react-dom: 19.3.0-canary-d2908752-20260119 + react: 19.3.0-canary-b546603b-20260121 + react-dom: 19.3.0-canary-b546603b-20260121 tailwindcss: ^3.4.14 || ^4.0.0 peerDependenciesMeta: '@types/react': @@ -13092,12 +13092,12 @@ packages: lucide-react@0.383.0: resolution: {integrity: sha512-13xlG0CQCJtzjSQYwwJ3WRqMHtRj3EXmLlorrARt7y+IHnxUCp3XyFNL1DfaGySWxHObDvnu1u1dV+0VMKHUSg==} peerDependencies: - react: 19.3.0-canary-d2908752-20260119 + react: 19.3.0-canary-b546603b-20260121 lucide-react@0.554.0: resolution: {integrity: sha512-St+z29uthEJVx0Is7ellNkgTEhaeSoA42I7JjOCBCrc5X6LYMGSv0P/2uS5HDLTExP5tpiqRD2PyUEOS6s9UXA==} peerDependencies: - react: 19.3.0-canary-d2908752-20260119 + react: 19.3.0-canary-b546603b-20260121 lz-string@1.5.0: resolution: {integrity: sha512-h5bgJWpxJNswbU7qCrV0tIKQCaS3blPDrqKWx+QxzuzL1zGUzij9XCWLrSLsJPu5t+eWA/ycetzYAO5IOMcWAQ==} @@ -13893,8 +13893,8 @@ packages: next-themes@0.4.6: resolution: {integrity: sha512-pZvgD5L0IEvX5/9GWyHMf3m8BKiVQwsCMHfoFosXtXBMnaS0ZnIJ9ST4b4NqLVKDEm8QBxoNNGNaBv2JNF6XNA==} peerDependencies: - react: 19.3.0-canary-d2908752-20260119 - react-dom: 19.3.0-canary-d2908752-20260119 + react: 19.3.0-canary-b546603b-20260121 + react-dom: 19.3.0-canary-b546603b-20260121 next-tick@1.0.0: resolution: {integrity: sha512-mc/caHeUcdjnC/boPWJefDr4KUIWQNv+tlnFnJd38QMou86QtxQzBJfxgGRzvx8jazYRqrVlaHarfO72uNxPOg==} @@ -13908,8 +13908,8 @@ packages: '@opentelemetry/api': ^1.1.0 '@playwright/test': ^1.51.1 babel-plugin-react-compiler: '*' - react: 19.3.0-canary-d2908752-20260119 - react-dom: 19.3.0-canary-d2908752-20260119 + react: 19.3.0-canary-b546603b-20260121 + react-dom: 19.3.0-canary-b546603b-20260121 sass: ^1.3.0 peerDependenciesMeta: '@opentelemetry/api': @@ -13930,8 +13930,8 @@ packages: '@opentelemetry/api': ^1.1.0 '@playwright/test': ^1.51.1 babel-plugin-react-compiler: '*' - react: 19.3.0-canary-d2908752-20260119 - react-dom: 19.3.0-canary-d2908752-20260119 + react: 19.3.0-canary-b546603b-20260121 + react-dom: 19.3.0-canary-b546603b-20260121 sass: ^1.3.0 peerDependenciesMeta: '@opentelemetry/api': @@ -15823,23 +15823,23 @@ packages: resolution: {integrity: sha512-APPU8HB2uZnpl6Vt/+0AFoVYgSRtfiP6FLrZgPPTDmqSb2R4qZRbgd0A3VzIFxDt5e+Fozjx79WjLWnF69DK8g==} engines: {node: '>=16.14.0'} - react-dom@0.0.0-experimental-d2908752-20260119: - resolution: {integrity: sha512-jm2r9Ny+gXQ0ZPIP4F4zEFtgxyBBXQRok0ZcO1uX/4mOu4K0FbuFKQfcqj/8CZ6wE6CbVyt5AxnMFhDTHKXwgg==} + react-dom@0.0.0-experimental-b546603b-20260121: + resolution: {integrity: sha512-nROauGxSWJk6jwA5KYBeOF4SimpEXFEhP2uwqdi8+MUiRF653EWFJlwDigfxT3L+CfJwKOBGpKZB7EKlYyq6lA==} peerDependencies: - react: 19.3.0-canary-d2908752-20260119 + react: 19.3.0-canary-b546603b-20260121 - react-dom@19.3.0-canary-d2908752-20260119: - resolution: {integrity: sha512-OlA7LXBhWscYEZMM+K4AqUxTmX08G5Hf2Cd0qutQGu8Hvp3cHl4G9Hgb7evW7X53l8S/Eyij6y0UeyntJQ6WAA==} + react-dom@19.3.0-canary-b546603b-20260121: + resolution: {integrity: sha512-oLuX+l/WAx6oN8MVeTRMLPXf7ZnNU4/FcDzYXwAWNrERUU7lHLsfqjkEB8IvrS4mpX83VtoZMno6vU3PvZNLzQ==} peerDependencies: - react: 19.3.0-canary-d2908752-20260119 + react: 19.3.0-canary-b546603b-20260121 react-dom@19.3.0-canary-fd524fe0-20251121: resolution: {integrity: sha512-+M3m+8ysDcPmt7ncitPOX5O71OOKF6lq6INFZFUMJjEGDxvl4CS2D41DJG5MnXcwiWTZLAp/uILZtt4sKTRSyQ==} peerDependencies: - react: 19.3.0-canary-d2908752-20260119 + react: 19.3.0-canary-b546603b-20260121 - react-is@19.3.0-canary-d2908752-20260119: - resolution: {integrity: sha512-boDMxJH0JnS8VZZpEacxfKo4PN/xeKck8WqxseEGtJ9o9NpGeb0IbAHZ3oqGxsGl71S2R0TrH+eFCc8ZVyxSUQ==} + react-is@19.3.0-canary-b546603b-20260121: + resolution: {integrity: sha512-EdEtarX66byu3NHO2at523tSsNkMCUq0Lo5LT5Js7XOfYLsZ0gdYFmoqrR9J9utzKKXOm7Vcu28UxazgdtIO4g==} react-is@19.3.0-canary-fd524fe0-20251121: resolution: {integrity: sha512-06VG41yCv5V7FPCLxo4hBaiLEoReJ35LK9VvEqveBJq5cbEhakZznJLnPU1oJ3CCrL4DyBsPXw9EiYlrOL8c3Q==} @@ -15850,14 +15850,14 @@ packages: react-medium-image-zoom@5.3.0: resolution: {integrity: sha512-RCIzVlsKqy3BYgGgYbolUfuvx0aSKC7YhX/IJGEp+WJxsqdIVYJHkBdj++FAj6VD7RiWj6VVmdCfa/9vJE9hZg==} peerDependencies: - react: 19.3.0-canary-d2908752-20260119 - react-dom: 19.3.0-canary-d2908752-20260119 + react: 19.3.0-canary-b546603b-20260121 + react-dom: 19.3.0-canary-b546603b-20260121 react-number-format@5.4.0: resolution: {integrity: sha512-NWdICrqLhI7rAS8yUeLVd6Wr4cN7UjJ9IBTS0f/a9i7UB4x4Ti70kGnksBtZ7o4Z7YRbvCMMR/jQmkoOBa/4fg==} peerDependencies: - react: 19.3.0-canary-d2908752-20260119 - react-dom: 19.3.0-canary-d2908752-20260119 + react: 19.3.0-canary-b546603b-20260121 + react-dom: 19.3.0-canary-b546603b-20260121 react-refresh@0.12.0: resolution: {integrity: sha512-suLIhrU2IHKL5JEKR/fAwJv7bbeq4kJ+pJopf77jHwuR+HmJS/HbrPIGsTBUVfw7tXPOmYv7UJ7PCaN49e8x4A==} @@ -15868,7 +15868,7 @@ packages: engines: {node: '>=10'} peerDependencies: '@types/react': 19.2.2 - react: 19.3.0-canary-d2908752-20260119 + react: 19.3.0-canary-b546603b-20260121 peerDependenciesMeta: '@types/react': optional: true @@ -15878,7 +15878,7 @@ packages: engines: {node: '>=10'} peerDependencies: '@types/react': 19.2.2 - react: 19.3.0-canary-d2908752-20260119 + react: 19.3.0-canary-b546603b-20260121 peerDependenciesMeta: '@types/react': optional: true @@ -15888,7 +15888,7 @@ packages: engines: {node: '>=10'} peerDependencies: '@types/react': 19.2.2 - react: 19.3.0-canary-d2908752-20260119 + react: 19.3.0-canary-b546603b-20260121 peerDependenciesMeta: '@types/react': optional: true @@ -15898,58 +15898,58 @@ packages: engines: {node: '>=10'} peerDependencies: '@types/react': 19.2.2 - react: 19.3.0-canary-d2908752-20260119 + react: 19.3.0-canary-b546603b-20260121 peerDependenciesMeta: '@types/react': optional: true - react-server-dom-turbopack@0.0.0-experimental-d2908752-20260119: - resolution: {integrity: sha512-jjL9lqrZUrb2Ea5u1/cEBzmU8J30STTj+6w6hI5edFcOYTA1bsMfOZypynozPQS4yxrS+cU8Xaa97PDuGgYMvQ==} + react-server-dom-turbopack@0.0.0-experimental-b546603b-20260121: + resolution: {integrity: sha512-hxNB+zppbaV6Fu8CGLzI+mDdnTMCHcpyAmI1Mw+LwLHxQzYg+DfOs/GKvk7nxwPmsKlkh4DgAzBSMmUKekKatQ==} engines: {node: '>=0.10.0'} peerDependencies: - react: 19.3.0-canary-d2908752-20260119 - react-dom: 19.3.0-canary-d2908752-20260119 + react: 19.3.0-canary-b546603b-20260121 + react-dom: 19.3.0-canary-b546603b-20260121 - react-server-dom-turbopack@19.3.0-canary-d2908752-20260119: - resolution: {integrity: sha512-8e5H1d8CngVos1VvBGdrdjEZ1KbSV9viijKP5QQPlAHp6yuRfZ/7lF8jIncs8kuyuohFwdN039x5kTC178XHWw==} + react-server-dom-turbopack@19.3.0-canary-b546603b-20260121: + resolution: {integrity: sha512-CrW9TgOo0WvcdYnA7q5fx3HRD/ikJLT3IuLcontzcMCNA2eLEHpY/0k1gT/ZOg2x65K3eM4Mcs9pRAQHsexGNg==} engines: {node: '>=0.10.0'} peerDependencies: - react: 19.3.0-canary-d2908752-20260119 - react-dom: 19.3.0-canary-d2908752-20260119 + react: 19.3.0-canary-b546603b-20260121 + react-dom: 19.3.0-canary-b546603b-20260121 - react-server-dom-webpack@0.0.0-experimental-d2908752-20260119: - resolution: {integrity: sha512-pxwbY/5mTGY8OnYtKm014AYAz4cPiLLOUFi6YbsBh9w/MCUu2CGZtKEqafZgxNJDTP4yR+sttvBYvBD4OzHzhQ==} + react-server-dom-webpack@0.0.0-experimental-b546603b-20260121: + resolution: {integrity: sha512-9IuD4ObcWWYwLov/o3Vt9OK4QTvIV8XgY9X+reGX/RHQncyZvnF6fjrqY4mnWA5LgQgHcNNIsXXW/ME9Rz5Pyg==} engines: {node: '>=0.10.0'} peerDependencies: - react: 19.3.0-canary-d2908752-20260119 - react-dom: 19.3.0-canary-d2908752-20260119 + react: 19.3.0-canary-b546603b-20260121 + react-dom: 19.3.0-canary-b546603b-20260121 webpack: 5.98.0 - react-server-dom-webpack@19.3.0-canary-d2908752-20260119: - resolution: {integrity: sha512-Y6uLLapemzYfSrDtMkNoB+gjvaQldGvvoRfoZvJFix/TwVR5wWGwvyzeNw8/Bbp32Q7+Jr9ghxyiLuY4Gd8iVA==} + react-server-dom-webpack@19.3.0-canary-b546603b-20260121: + resolution: {integrity: sha512-D0PSB68T/YKDKwfjpy6I/60tIfk91jMXEspHFS/8Ykln3FB0g2OVD0zfYURnvyEzER1/iNFo/L4TDUgiqeNbxQ==} engines: {node: '>=0.10.0'} peerDependencies: - react: 19.3.0-canary-d2908752-20260119 - react-dom: 19.3.0-canary-d2908752-20260119 + react: 19.3.0-canary-b546603b-20260121 + react-dom: 19.3.0-canary-b546603b-20260121 webpack: 5.98.0 react-shallow-renderer@16.15.0: resolution: {integrity: sha512-oScf2FqQ9LFVQgA73vr86xl2NaOIX73rh+YFqcOp68CWj56tSfgtGKrEbyhCj0rSijyG9M1CYprTh39fBi5hzA==} peerDependencies: - react: 19.3.0-canary-d2908752-20260119 + react: 19.3.0-canary-b546603b-20260121 react-ssr-prepass@1.0.8: resolution: {integrity: sha512-O0gfRA1SaK+9ITKxqfnXsej2jF+OHGP/+GxD4unROQaM/0/UczGF9fuF+wTboxaQoKdIf4FvS3h/OigWh704VA==} peerDependencies: - react: 19.3.0-canary-d2908752-20260119 - react-is: 19.3.0-canary-d2908752-20260119 + react: 19.3.0-canary-b546603b-20260121 + react-is: 19.3.0-canary-b546603b-20260121 react-style-singleton@2.2.1: resolution: {integrity: sha512-ZWj0fHEMyWkHzKYUr2Bs/4zU6XLmq9HsgBURm7g5pAVfyn49DgUiNgY2d4lXRlYSiCif9YBGpQleewkcqddc7g==} engines: {node: '>=10'} peerDependencies: '@types/react': 19.2.2 - react: 19.3.0-canary-d2908752-20260119 + react: 19.3.0-canary-b546603b-20260121 peerDependenciesMeta: '@types/react': optional: true @@ -15959,7 +15959,7 @@ packages: engines: {node: '>=10'} peerDependencies: '@types/react': 19.2.2 - react: 19.3.0-canary-d2908752-20260119 + react: 19.3.0-canary-b546603b-20260121 peerDependenciesMeta: '@types/react': optional: true @@ -15967,26 +15967,26 @@ packages: react-test-renderer@18.2.0: resolution: {integrity: sha512-JWD+aQ0lh2gvh4NM3bBM42Kx+XybOxCpgYK7F8ugAlpaTSnWsX+39Z4XkOykGZAHrjwwTZT3x3KxswVWxHPUqA==} peerDependencies: - react: 19.3.0-canary-d2908752-20260119 + react: 19.3.0-canary-b546603b-20260121 react-textarea-autosize@8.5.3: resolution: {integrity: sha512-XT1024o2pqCuZSuBt9FwHlaDeNtVrtCXu0Rnz88t1jUGheCLa3PhjE1GH8Ctm2axEtvdCl5SUHYschyQ0L5QHQ==} engines: {node: '>=10'} peerDependencies: - react: 19.3.0-canary-d2908752-20260119 + react: 19.3.0-canary-b546603b-20260121 react-virtualized@9.22.3: resolution: {integrity: sha512-MKovKMxWTcwPSxE1kK1HcheQTWfuCxAuBoSTf2gwyMM21NdX/PXUhnoP8Uc5dRKd+nKm8v41R36OellhdCpkrw==} peerDependencies: - react: 19.3.0-canary-d2908752-20260119 - react-dom: 19.3.0-canary-d2908752-20260119 + react: 19.3.0-canary-b546603b-20260121 + react-dom: 19.3.0-canary-b546603b-20260121 - react@0.0.0-experimental-d2908752-20260119: - resolution: {integrity: sha512-QVj/NX4O7HZ/RFBfvIEtlDq/vkIhJtaruGBpX0QSTGpjqADCb3VSPaliwUQEgu/VpSDimEZgXBTwVg2ti901HA==} + react@0.0.0-experimental-b546603b-20260121: + resolution: {integrity: sha512-4O/RaGAegWvCu1IYGomFSCz9BSqeAmOlnYBs42YdpIeUriJTkKw/iQAMk5Du3wE6CuSfFNkmkS8aM+DbjhslhQ==} engines: {node: '>=0.10.0'} - react@19.3.0-canary-d2908752-20260119: - resolution: {integrity: sha512-LeCk1lP/SLGVVB/kDw13ls/OszLcHdIWMNlhGsMaxeTVGCx9uz/9BZkBLTmxednNQeqNyLy8MARpzMs4xbfE1Q==} + react@19.3.0-canary-b546603b-20260121: + resolution: {integrity: sha512-nxOYGo76zHV+IBy6SL7QDwCpEl4b9p0+HorirjqVVrSBP+9Wys1JWOD6wK9Q6rZLrxkHkwRQDr7HZOQMezk64Q==} engines: {node: '>=0.10.0'} react@19.3.0-canary-fd524fe0-20251121: @@ -16593,11 +16593,11 @@ packages: resolution: {integrity: sha512-xAg7SOnEhrm5zI3puOOKyy1OMcMlIJZYNJY7xLBwSze0UjhPLnWfj2GF2EpT0jmzaJKIWKHLsaSSajf35bcYnA==} engines: {node: '>=v12.22.7'} - scheduler@0.0.0-experimental-d2908752-20260119: - resolution: {integrity: sha512-CVNnuY1ENiyNxuaGgaV8zZnHe2w9IV7DsiwKfaEv14Hr6IQ8ZlrLwwhV+ey3o8i7OWz0n1n0GkGG3DPsG4xV7Q==} + scheduler@0.0.0-experimental-b546603b-20260121: + resolution: {integrity: sha512-Uo77EXo6vKJpowRkbAL9Z3CIzKHKO4FhdjngfYHgprZnblEz2u6v0Ym6q+dj7J9dzruEsX77h1NB0UdzgXCmAA==} - scheduler@0.28.0-canary-d2908752-20260119: - resolution: {integrity: sha512-znKT5MJ6xngdX11+2iufeOYgRhjX5p48868JP06uXcTLWNNFTuDc9SQNg5hnGpy+lA5CpemBBGNOFJv3fKdpcw==} + scheduler@0.28.0-canary-b546603b-20260121: + resolution: {integrity: sha512-chXVxWygOICQlnd99zygWLbzU8Jl03crwCKI/PT0V+UmQpBre8kwAkqn0cqfRA09xAIjrd9UPBLkXDfqs/BBzQ==} schema-utils@2.7.1: resolution: {integrity: sha512-SHiNtMOUGWBQJwzISiVYKu82GiV4QYGePp3odlY1tuKO7gPtphAT5R/py0fA6xtbgLL/RvtJZnU9b8s0F1q0Xg==} @@ -17282,7 +17282,7 @@ packages: peerDependencies: '@babel/core': '*' babel-plugin-macros: '*' - react: 19.3.0-canary-d2908752-20260119 + react: 19.3.0-canary-b546603b-20260121 peerDependenciesMeta: '@babel/core': optional: true @@ -17369,7 +17369,7 @@ packages: swr@2.2.4: resolution: {integrity: sha512-njiZ/4RiIhoOlAaLYDqwz5qH/KZXVilRLvomrx83HjzCWTfa+InyfAjv05PSFxnmLzZkNO9ZfvgoqzAaEI4sGQ==} peerDependencies: - react: 19.3.0-canary-d2908752-20260119 + react: 19.3.0-canary-b546603b-20260121 symbol-observable@1.0.1: resolution: {integrity: sha512-Kb3PrPYz4HanVF1LVGuAdW6LoVgIwjUYJGzFe7NDrBLCN4lsV/5J0MFurV+ygS4bRVwrCEt2c7MQ1R2a72oJDw==} @@ -18232,7 +18232,7 @@ packages: engines: {node: '>=10'} peerDependencies: '@types/react': 19.2.2 - react: 19.3.0-canary-d2908752-20260119 + react: 19.3.0-canary-b546603b-20260121 peerDependenciesMeta: '@types/react': optional: true @@ -18242,7 +18242,7 @@ packages: engines: {node: '>=10'} peerDependencies: '@types/react': 19.2.2 - react: 19.3.0-canary-d2908752-20260119 + react: 19.3.0-canary-b546603b-20260121 peerDependenciesMeta: '@types/react': optional: true @@ -18250,13 +18250,13 @@ packages: use-composed-ref@1.3.0: resolution: {integrity: sha512-GLMG0Jc/jiKov/3Ulid1wbv3r54K9HlMW29IWcDFPEqFkSO2nS0MuefWgMJpeHQ9YJeXDL3ZUF+P3jdXlZX/cQ==} peerDependencies: - react: 19.3.0-canary-d2908752-20260119 + react: 19.3.0-canary-b546603b-20260121 use-isomorphic-layout-effect@1.1.2: resolution: {integrity: sha512-49L8yCO3iGT/ZF9QttjwLF/ZD9Iwto5LnH5LmEdk/6cFmXddqi2ulF0edxTwjj+7mqvpVVGQWvbXZdn32wRSHA==} peerDependencies: '@types/react': '*' - react: 19.3.0-canary-d2908752-20260119 + react: 19.3.0-canary-b546603b-20260121 peerDependenciesMeta: '@types/react': optional: true @@ -18265,7 +18265,7 @@ packages: resolution: {integrity: sha512-xA+AVm/Wlg3e2P/JiItTziwS7FK92LWrDB0p+hgXloIMuVCeJJ8v6f0eeHyPZaJrM+usM1FkFfbNCrJGs8A/zw==} peerDependencies: '@types/react': '*' - react: 19.3.0-canary-d2908752-20260119 + react: 19.3.0-canary-b546603b-20260121 peerDependenciesMeta: '@types/react': optional: true @@ -18275,7 +18275,7 @@ packages: engines: {node: '>=10'} peerDependencies: '@types/react': 19.2.2 - react: 19.3.0-canary-d2908752-20260119 + react: 19.3.0-canary-b546603b-20260121 peerDependenciesMeta: '@types/react': optional: true @@ -18285,7 +18285,7 @@ packages: engines: {node: '>=10'} peerDependencies: '@types/react': 19.2.2 - react: 19.3.0-canary-d2908752-20260119 + react: 19.3.0-canary-b546603b-20260121 peerDependenciesMeta: '@types/react': optional: true @@ -18293,7 +18293,7 @@ packages: use-sync-external-store@1.5.0: resolution: {integrity: sha512-Rb46I4cGGVBmjamjphe8L/UnvJD+uPPtTkNvX5mZgqdbavhI4EbgIWJiIHXJ8bc/i9EQGPRh4DwEURJ552Do0A==} peerDependencies: - react: 19.3.0-canary-d2908752-20260119 + react: 19.3.0-canary-b546603b-20260121 util-deprecate@1.0.2: resolution: {integrity: sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==} @@ -19908,28 +19908,28 @@ snapshots: '@babel/helper-string-parser': 7.25.9 '@babel/helper-validator-identifier': 7.25.9 - '@base-ui-components/react@1.0.0-beta.2(@types/react@19.2.2)(react-dom@19.3.0-canary-d2908752-20260119(react@19.3.0-canary-d2908752-20260119))(react@19.3.0-canary-d2908752-20260119)': + '@base-ui-components/react@1.0.0-beta.2(@types/react@19.2.2)(react-dom@19.3.0-canary-b546603b-20260121(react@19.3.0-canary-b546603b-20260121))(react@19.3.0-canary-b546603b-20260121)': dependencies: '@babel/runtime': 7.27.6 - '@base-ui-components/utils': 0.1.0(@types/react@19.2.2)(react-dom@19.3.0-canary-d2908752-20260119(react@19.3.0-canary-d2908752-20260119))(react@19.3.0-canary-d2908752-20260119) - '@floating-ui/react-dom': 2.1.5(react-dom@19.3.0-canary-d2908752-20260119(react@19.3.0-canary-d2908752-20260119))(react@19.3.0-canary-d2908752-20260119) + '@base-ui-components/utils': 0.1.0(@types/react@19.2.2)(react-dom@19.3.0-canary-b546603b-20260121(react@19.3.0-canary-b546603b-20260121))(react@19.3.0-canary-b546603b-20260121) + '@floating-ui/react-dom': 2.1.5(react-dom@19.3.0-canary-b546603b-20260121(react@19.3.0-canary-b546603b-20260121))(react@19.3.0-canary-b546603b-20260121) '@floating-ui/utils': 0.2.10 - react: 19.3.0-canary-d2908752-20260119 - react-dom: 19.3.0-canary-d2908752-20260119(react@19.3.0-canary-d2908752-20260119) + react: 19.3.0-canary-b546603b-20260121 + react-dom: 19.3.0-canary-b546603b-20260121(react@19.3.0-canary-b546603b-20260121) reselect: 5.1.1 tabbable: 6.2.0 - use-sync-external-store: 1.5.0(react@19.3.0-canary-d2908752-20260119) + use-sync-external-store: 1.5.0(react@19.3.0-canary-b546603b-20260121) optionalDependencies: '@types/react': 19.2.2 - '@base-ui-components/utils@0.1.0(@types/react@19.2.2)(react-dom@19.3.0-canary-d2908752-20260119(react@19.3.0-canary-d2908752-20260119))(react@19.3.0-canary-d2908752-20260119)': + '@base-ui-components/utils@0.1.0(@types/react@19.2.2)(react-dom@19.3.0-canary-b546603b-20260121(react@19.3.0-canary-b546603b-20260121))(react@19.3.0-canary-b546603b-20260121)': dependencies: '@babel/runtime': 7.27.6 '@floating-ui/utils': 0.2.10 - react: 19.3.0-canary-d2908752-20260119 - react-dom: 19.3.0-canary-d2908752-20260119(react@19.3.0-canary-d2908752-20260119) + react: 19.3.0-canary-b546603b-20260121 + react-dom: 19.3.0-canary-b546603b-20260121(react@19.3.0-canary-b546603b-20260121) reselect: 5.1.1 - use-sync-external-store: 1.5.0(react@19.3.0-canary-d2908752-20260119) + use-sync-external-store: 1.5.0(react@19.3.0-canary-b546603b-20260121) optionalDependencies: '@types/react': 19.2.2 @@ -20102,17 +20102,17 @@ snapshots: '@emotion/memoize@0.8.1': {} - '@emotion/react@11.11.1(@types/react@19.2.2)(react@19.3.0-canary-d2908752-20260119)': + '@emotion/react@11.11.1(@types/react@19.2.2)(react@19.3.0-canary-b546603b-20260121)': dependencies: '@babel/runtime': 7.27.0 '@emotion/babel-plugin': 11.11.0 '@emotion/cache': 11.11.0 '@emotion/serialize': 1.1.2 - '@emotion/use-insertion-effect-with-fallbacks': 1.0.1(react@19.3.0-canary-d2908752-20260119) + '@emotion/use-insertion-effect-with-fallbacks': 1.0.1(react@19.3.0-canary-b546603b-20260121) '@emotion/utils': 1.2.1 '@emotion/weak-memoize': 0.3.1 hoist-non-react-statics: 3.3.2 - react: 19.3.0-canary-d2908752-20260119 + react: 19.3.0-canary-b546603b-20260121 optionalDependencies: '@types/react': 19.2.2 transitivePeerDependencies: @@ -20130,9 +20130,9 @@ snapshots: '@emotion/unitless@0.8.1': {} - '@emotion/use-insertion-effect-with-fallbacks@1.0.1(react@19.3.0-canary-d2908752-20260119)': + '@emotion/use-insertion-effect-with-fallbacks@1.0.1(react@19.3.0-canary-b546603b-20260121)': dependencies: - react: 19.3.0-canary-d2908752-20260119 + react: 19.3.0-canary-b546603b-20260121 '@emotion/utils@1.2.1': {} @@ -20555,11 +20555,11 @@ snapshots: react: 19.3.0-canary-fd524fe0-20251121 react-dom: 19.3.0-canary-fd524fe0-20251121(react@19.3.0-canary-fd524fe0-20251121) - '@floating-ui/react-dom@2.1.5(react-dom@19.3.0-canary-d2908752-20260119(react@19.3.0-canary-d2908752-20260119))(react@19.3.0-canary-d2908752-20260119)': + '@floating-ui/react-dom@2.1.5(react-dom@19.3.0-canary-b546603b-20260121(react@19.3.0-canary-b546603b-20260121))(react@19.3.0-canary-b546603b-20260121)': dependencies: '@floating-ui/dom': 1.7.3 - react: 19.3.0-canary-d2908752-20260119 - react-dom: 19.3.0-canary-d2908752-20260119(react@19.3.0-canary-d2908752-20260119) + react: 19.3.0-canary-b546603b-20260121 + react-dom: 19.3.0-canary-b546603b-20260121(react@19.3.0-canary-b546603b-20260121) '@floating-ui/react@0.26.16(react-dom@19.3.0-canary-fd524fe0-20251121(react@19.3.0-canary-fd524fe0-20251121))(react@19.3.0-canary-fd524fe0-20251121)': dependencies: @@ -21519,11 +21519,11 @@ snapshots: transitivePeerDependencies: - supports-color - '@mdx-js/react@2.2.1(react@19.3.0-canary-d2908752-20260119)': + '@mdx-js/react@2.2.1(react@19.3.0-canary-b546603b-20260121)': dependencies: '@types/mdx': 2.0.13 '@types/react': 19.2.2 - react: 19.3.0-canary-d2908752-20260119 + react: 19.3.0-canary-b546603b-20260121 '@mdx-js/react@2.2.1(react@19.3.0-canary-fd524fe0-20251121)': dependencies: @@ -21531,11 +21531,11 @@ snapshots: '@types/react': 19.2.2 react: 19.3.0-canary-fd524fe0-20251121 - '@mdx-js/react@3.1.0(@types/react@19.2.2)(react@19.3.0-canary-d2908752-20260119)': + '@mdx-js/react@3.1.0(@types/react@19.2.2)(react@19.3.0-canary-b546603b-20260121)': dependencies: '@types/mdx': 2.0.13 '@types/react': 19.2.2 - react: 19.3.0-canary-d2908752-20260119 + react: 19.3.0-canary-b546603b-20260121 '@modelcontextprotocol/sdk@1.18.1': dependencies: @@ -22305,749 +22305,749 @@ snapshots: '@radix-ui/primitive@1.1.3': {} - '@radix-ui/react-accordion@1.2.12(@types/react-dom@19.2.1(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.3.0-canary-d2908752-20260119(react@19.3.0-canary-d2908752-20260119))(react@19.3.0-canary-d2908752-20260119)': + '@radix-ui/react-accordion@1.2.12(@types/react-dom@19.2.1(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.3.0-canary-b546603b-20260121(react@19.3.0-canary-b546603b-20260121))(react@19.3.0-canary-b546603b-20260121)': dependencies: '@radix-ui/primitive': 1.1.3 - '@radix-ui/react-collapsible': 1.1.12(@types/react-dom@19.2.1(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.3.0-canary-d2908752-20260119(react@19.3.0-canary-d2908752-20260119))(react@19.3.0-canary-d2908752-20260119) - '@radix-ui/react-collection': 1.1.7(@types/react-dom@19.2.1(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.3.0-canary-d2908752-20260119(react@19.3.0-canary-d2908752-20260119))(react@19.3.0-canary-d2908752-20260119) - '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.2)(react@19.3.0-canary-d2908752-20260119) - '@radix-ui/react-context': 1.1.2(@types/react@19.2.2)(react@19.3.0-canary-d2908752-20260119) - '@radix-ui/react-direction': 1.1.1(@types/react@19.2.2)(react@19.3.0-canary-d2908752-20260119) - '@radix-ui/react-id': 1.1.1(@types/react@19.2.2)(react@19.3.0-canary-d2908752-20260119) - '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.1(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.3.0-canary-d2908752-20260119(react@19.3.0-canary-d2908752-20260119))(react@19.3.0-canary-d2908752-20260119) - '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@19.2.2)(react@19.3.0-canary-d2908752-20260119) - react: 19.3.0-canary-d2908752-20260119 - react-dom: 19.3.0-canary-d2908752-20260119(react@19.3.0-canary-d2908752-20260119) + '@radix-ui/react-collapsible': 1.1.12(@types/react-dom@19.2.1(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.3.0-canary-b546603b-20260121(react@19.3.0-canary-b546603b-20260121))(react@19.3.0-canary-b546603b-20260121) + '@radix-ui/react-collection': 1.1.7(@types/react-dom@19.2.1(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.3.0-canary-b546603b-20260121(react@19.3.0-canary-b546603b-20260121))(react@19.3.0-canary-b546603b-20260121) + '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.2)(react@19.3.0-canary-b546603b-20260121) + '@radix-ui/react-context': 1.1.2(@types/react@19.2.2)(react@19.3.0-canary-b546603b-20260121) + '@radix-ui/react-direction': 1.1.1(@types/react@19.2.2)(react@19.3.0-canary-b546603b-20260121) + '@radix-ui/react-id': 1.1.1(@types/react@19.2.2)(react@19.3.0-canary-b546603b-20260121) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.1(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.3.0-canary-b546603b-20260121(react@19.3.0-canary-b546603b-20260121))(react@19.3.0-canary-b546603b-20260121) + '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@19.2.2)(react@19.3.0-canary-b546603b-20260121) + react: 19.3.0-canary-b546603b-20260121 + react-dom: 19.3.0-canary-b546603b-20260121(react@19.3.0-canary-b546603b-20260121) optionalDependencies: '@types/react': 19.2.2 '@types/react-dom': 19.2.1(@types/react@19.2.2) - '@radix-ui/react-arrow@1.1.0(@types/react-dom@19.2.1(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.3.0-canary-d2908752-20260119(react@19.3.0-canary-d2908752-20260119))(react@19.3.0-canary-d2908752-20260119)': + '@radix-ui/react-arrow@1.1.0(@types/react-dom@19.2.1(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.3.0-canary-b546603b-20260121(react@19.3.0-canary-b546603b-20260121))(react@19.3.0-canary-b546603b-20260121)': dependencies: - '@radix-ui/react-primitive': 2.0.0(@types/react-dom@19.2.1(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.3.0-canary-d2908752-20260119(react@19.3.0-canary-d2908752-20260119))(react@19.3.0-canary-d2908752-20260119) - react: 19.3.0-canary-d2908752-20260119 - react-dom: 19.3.0-canary-d2908752-20260119(react@19.3.0-canary-d2908752-20260119) + '@radix-ui/react-primitive': 2.0.0(@types/react-dom@19.2.1(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.3.0-canary-b546603b-20260121(react@19.3.0-canary-b546603b-20260121))(react@19.3.0-canary-b546603b-20260121) + react: 19.3.0-canary-b546603b-20260121 + react-dom: 19.3.0-canary-b546603b-20260121(react@19.3.0-canary-b546603b-20260121) optionalDependencies: '@types/react': 19.2.2 '@types/react-dom': 19.2.1(@types/react@19.2.2) - '@radix-ui/react-arrow@1.1.1(@types/react-dom@19.2.1(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.3.0-canary-d2908752-20260119(react@19.3.0-canary-d2908752-20260119))(react@19.3.0-canary-d2908752-20260119)': + '@radix-ui/react-arrow@1.1.1(@types/react-dom@19.2.1(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.3.0-canary-b546603b-20260121(react@19.3.0-canary-b546603b-20260121))(react@19.3.0-canary-b546603b-20260121)': dependencies: - '@radix-ui/react-primitive': 2.0.1(@types/react-dom@19.2.1(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.3.0-canary-d2908752-20260119(react@19.3.0-canary-d2908752-20260119))(react@19.3.0-canary-d2908752-20260119) - react: 19.3.0-canary-d2908752-20260119 - react-dom: 19.3.0-canary-d2908752-20260119(react@19.3.0-canary-d2908752-20260119) + '@radix-ui/react-primitive': 2.0.1(@types/react-dom@19.2.1(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.3.0-canary-b546603b-20260121(react@19.3.0-canary-b546603b-20260121))(react@19.3.0-canary-b546603b-20260121) + react: 19.3.0-canary-b546603b-20260121 + react-dom: 19.3.0-canary-b546603b-20260121(react@19.3.0-canary-b546603b-20260121) optionalDependencies: '@types/react': 19.2.2 '@types/react-dom': 19.2.1(@types/react@19.2.2) - '@radix-ui/react-arrow@1.1.7(@types/react-dom@19.2.1(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.3.0-canary-d2908752-20260119(react@19.3.0-canary-d2908752-20260119))(react@19.3.0-canary-d2908752-20260119)': + '@radix-ui/react-arrow@1.1.7(@types/react-dom@19.2.1(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.3.0-canary-b546603b-20260121(react@19.3.0-canary-b546603b-20260121))(react@19.3.0-canary-b546603b-20260121)': dependencies: - '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.1(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.3.0-canary-d2908752-20260119(react@19.3.0-canary-d2908752-20260119))(react@19.3.0-canary-d2908752-20260119) - react: 19.3.0-canary-d2908752-20260119 - react-dom: 19.3.0-canary-d2908752-20260119(react@19.3.0-canary-d2908752-20260119) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.1(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.3.0-canary-b546603b-20260121(react@19.3.0-canary-b546603b-20260121))(react@19.3.0-canary-b546603b-20260121) + react: 19.3.0-canary-b546603b-20260121 + react-dom: 19.3.0-canary-b546603b-20260121(react@19.3.0-canary-b546603b-20260121) optionalDependencies: '@types/react': 19.2.2 '@types/react-dom': 19.2.1(@types/react@19.2.2) - '@radix-ui/react-collapsible@1.1.12(@types/react-dom@19.2.1(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.3.0-canary-d2908752-20260119(react@19.3.0-canary-d2908752-20260119))(react@19.3.0-canary-d2908752-20260119)': + '@radix-ui/react-collapsible@1.1.12(@types/react-dom@19.2.1(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.3.0-canary-b546603b-20260121(react@19.3.0-canary-b546603b-20260121))(react@19.3.0-canary-b546603b-20260121)': dependencies: '@radix-ui/primitive': 1.1.3 - '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.2)(react@19.3.0-canary-d2908752-20260119) - '@radix-ui/react-context': 1.1.2(@types/react@19.2.2)(react@19.3.0-canary-d2908752-20260119) - '@radix-ui/react-id': 1.1.1(@types/react@19.2.2)(react@19.3.0-canary-d2908752-20260119) - '@radix-ui/react-presence': 1.1.5(@types/react-dom@19.2.1(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.3.0-canary-d2908752-20260119(react@19.3.0-canary-d2908752-20260119))(react@19.3.0-canary-d2908752-20260119) - '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.1(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.3.0-canary-d2908752-20260119(react@19.3.0-canary-d2908752-20260119))(react@19.3.0-canary-d2908752-20260119) - '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@19.2.2)(react@19.3.0-canary-d2908752-20260119) - '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.2.2)(react@19.3.0-canary-d2908752-20260119) - react: 19.3.0-canary-d2908752-20260119 - react-dom: 19.3.0-canary-d2908752-20260119(react@19.3.0-canary-d2908752-20260119) + '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.2)(react@19.3.0-canary-b546603b-20260121) + '@radix-ui/react-context': 1.1.2(@types/react@19.2.2)(react@19.3.0-canary-b546603b-20260121) + '@radix-ui/react-id': 1.1.1(@types/react@19.2.2)(react@19.3.0-canary-b546603b-20260121) + '@radix-ui/react-presence': 1.1.5(@types/react-dom@19.2.1(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.3.0-canary-b546603b-20260121(react@19.3.0-canary-b546603b-20260121))(react@19.3.0-canary-b546603b-20260121) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.1(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.3.0-canary-b546603b-20260121(react@19.3.0-canary-b546603b-20260121))(react@19.3.0-canary-b546603b-20260121) + '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@19.2.2)(react@19.3.0-canary-b546603b-20260121) + '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.2.2)(react@19.3.0-canary-b546603b-20260121) + react: 19.3.0-canary-b546603b-20260121 + react-dom: 19.3.0-canary-b546603b-20260121(react@19.3.0-canary-b546603b-20260121) optionalDependencies: '@types/react': 19.2.2 '@types/react-dom': 19.2.1(@types/react@19.2.2) - '@radix-ui/react-collection@1.1.1(@types/react-dom@19.2.1(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.3.0-canary-d2908752-20260119(react@19.3.0-canary-d2908752-20260119))(react@19.3.0-canary-d2908752-20260119)': + '@radix-ui/react-collection@1.1.1(@types/react-dom@19.2.1(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.3.0-canary-b546603b-20260121(react@19.3.0-canary-b546603b-20260121))(react@19.3.0-canary-b546603b-20260121)': dependencies: - '@radix-ui/react-compose-refs': 1.1.1(@types/react@19.2.2)(react@19.3.0-canary-d2908752-20260119) - '@radix-ui/react-context': 1.1.1(@types/react@19.2.2)(react@19.3.0-canary-d2908752-20260119) - '@radix-ui/react-primitive': 2.0.1(@types/react-dom@19.2.1(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.3.0-canary-d2908752-20260119(react@19.3.0-canary-d2908752-20260119))(react@19.3.0-canary-d2908752-20260119) - '@radix-ui/react-slot': 1.1.1(@types/react@19.2.2)(react@19.3.0-canary-d2908752-20260119) - react: 19.3.0-canary-d2908752-20260119 - react-dom: 19.3.0-canary-d2908752-20260119(react@19.3.0-canary-d2908752-20260119) + '@radix-ui/react-compose-refs': 1.1.1(@types/react@19.2.2)(react@19.3.0-canary-b546603b-20260121) + '@radix-ui/react-context': 1.1.1(@types/react@19.2.2)(react@19.3.0-canary-b546603b-20260121) + '@radix-ui/react-primitive': 2.0.1(@types/react-dom@19.2.1(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.3.0-canary-b546603b-20260121(react@19.3.0-canary-b546603b-20260121))(react@19.3.0-canary-b546603b-20260121) + '@radix-ui/react-slot': 1.1.1(@types/react@19.2.2)(react@19.3.0-canary-b546603b-20260121) + react: 19.3.0-canary-b546603b-20260121 + react-dom: 19.3.0-canary-b546603b-20260121(react@19.3.0-canary-b546603b-20260121) optionalDependencies: '@types/react': 19.2.2 '@types/react-dom': 19.2.1(@types/react@19.2.2) - '@radix-ui/react-collection@1.1.7(@types/react-dom@19.2.1(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.3.0-canary-d2908752-20260119(react@19.3.0-canary-d2908752-20260119))(react@19.3.0-canary-d2908752-20260119)': + '@radix-ui/react-collection@1.1.7(@types/react-dom@19.2.1(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.3.0-canary-b546603b-20260121(react@19.3.0-canary-b546603b-20260121))(react@19.3.0-canary-b546603b-20260121)': dependencies: - '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.2)(react@19.3.0-canary-d2908752-20260119) - '@radix-ui/react-context': 1.1.2(@types/react@19.2.2)(react@19.3.0-canary-d2908752-20260119) - '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.1(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.3.0-canary-d2908752-20260119(react@19.3.0-canary-d2908752-20260119))(react@19.3.0-canary-d2908752-20260119) - '@radix-ui/react-slot': 1.2.3(@types/react@19.2.2)(react@19.3.0-canary-d2908752-20260119) - react: 19.3.0-canary-d2908752-20260119 - react-dom: 19.3.0-canary-d2908752-20260119(react@19.3.0-canary-d2908752-20260119) + '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.2)(react@19.3.0-canary-b546603b-20260121) + '@radix-ui/react-context': 1.1.2(@types/react@19.2.2)(react@19.3.0-canary-b546603b-20260121) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.1(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.3.0-canary-b546603b-20260121(react@19.3.0-canary-b546603b-20260121))(react@19.3.0-canary-b546603b-20260121) + '@radix-ui/react-slot': 1.2.3(@types/react@19.2.2)(react@19.3.0-canary-b546603b-20260121) + react: 19.3.0-canary-b546603b-20260121 + react-dom: 19.3.0-canary-b546603b-20260121(react@19.3.0-canary-b546603b-20260121) optionalDependencies: '@types/react': 19.2.2 '@types/react-dom': 19.2.1(@types/react@19.2.2) - '@radix-ui/react-compose-refs@1.1.0(@types/react@19.2.2)(react@19.3.0-canary-d2908752-20260119)': + '@radix-ui/react-compose-refs@1.1.0(@types/react@19.2.2)(react@19.3.0-canary-b546603b-20260121)': dependencies: - react: 19.3.0-canary-d2908752-20260119 + react: 19.3.0-canary-b546603b-20260121 optionalDependencies: '@types/react': 19.2.2 - '@radix-ui/react-compose-refs@1.1.1(@types/react@19.2.2)(react@19.3.0-canary-d2908752-20260119)': + '@radix-ui/react-compose-refs@1.1.1(@types/react@19.2.2)(react@19.3.0-canary-b546603b-20260121)': dependencies: - react: 19.3.0-canary-d2908752-20260119 + react: 19.3.0-canary-b546603b-20260121 optionalDependencies: '@types/react': 19.2.2 - '@radix-ui/react-compose-refs@1.1.2(@types/react@19.2.2)(react@19.3.0-canary-d2908752-20260119)': + '@radix-ui/react-compose-refs@1.1.2(@types/react@19.2.2)(react@19.3.0-canary-b546603b-20260121)': dependencies: - react: 19.3.0-canary-d2908752-20260119 + react: 19.3.0-canary-b546603b-20260121 optionalDependencies: '@types/react': 19.2.2 - '@radix-ui/react-context@1.1.0(@types/react@19.2.2)(react@19.3.0-canary-d2908752-20260119)': + '@radix-ui/react-context@1.1.0(@types/react@19.2.2)(react@19.3.0-canary-b546603b-20260121)': dependencies: - react: 19.3.0-canary-d2908752-20260119 + react: 19.3.0-canary-b546603b-20260121 optionalDependencies: '@types/react': 19.2.2 - '@radix-ui/react-context@1.1.1(@types/react@19.2.2)(react@19.3.0-canary-d2908752-20260119)': + '@radix-ui/react-context@1.1.1(@types/react@19.2.2)(react@19.3.0-canary-b546603b-20260121)': dependencies: - react: 19.3.0-canary-d2908752-20260119 + react: 19.3.0-canary-b546603b-20260121 optionalDependencies: '@types/react': 19.2.2 - '@radix-ui/react-context@1.1.2(@types/react@19.2.2)(react@19.3.0-canary-d2908752-20260119)': + '@radix-ui/react-context@1.1.2(@types/react@19.2.2)(react@19.3.0-canary-b546603b-20260121)': dependencies: - react: 19.3.0-canary-d2908752-20260119 + react: 19.3.0-canary-b546603b-20260121 optionalDependencies: '@types/react': 19.2.2 - '@radix-ui/react-dialog@1.1.15(@types/react-dom@19.2.1(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.3.0-canary-d2908752-20260119(react@19.3.0-canary-d2908752-20260119))(react@19.3.0-canary-d2908752-20260119)': + '@radix-ui/react-dialog@1.1.15(@types/react-dom@19.2.1(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.3.0-canary-b546603b-20260121(react@19.3.0-canary-b546603b-20260121))(react@19.3.0-canary-b546603b-20260121)': dependencies: '@radix-ui/primitive': 1.1.3 - '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.2)(react@19.3.0-canary-d2908752-20260119) - '@radix-ui/react-context': 1.1.2(@types/react@19.2.2)(react@19.3.0-canary-d2908752-20260119) - '@radix-ui/react-dismissable-layer': 1.1.11(@types/react-dom@19.2.1(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.3.0-canary-d2908752-20260119(react@19.3.0-canary-d2908752-20260119))(react@19.3.0-canary-d2908752-20260119) - '@radix-ui/react-focus-guards': 1.1.3(@types/react@19.2.2)(react@19.3.0-canary-d2908752-20260119) - '@radix-ui/react-focus-scope': 1.1.7(@types/react-dom@19.2.1(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.3.0-canary-d2908752-20260119(react@19.3.0-canary-d2908752-20260119))(react@19.3.0-canary-d2908752-20260119) - '@radix-ui/react-id': 1.1.1(@types/react@19.2.2)(react@19.3.0-canary-d2908752-20260119) - '@radix-ui/react-portal': 1.1.9(@types/react-dom@19.2.1(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.3.0-canary-d2908752-20260119(react@19.3.0-canary-d2908752-20260119))(react@19.3.0-canary-d2908752-20260119) - '@radix-ui/react-presence': 1.1.5(@types/react-dom@19.2.1(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.3.0-canary-d2908752-20260119(react@19.3.0-canary-d2908752-20260119))(react@19.3.0-canary-d2908752-20260119) - '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.1(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.3.0-canary-d2908752-20260119(react@19.3.0-canary-d2908752-20260119))(react@19.3.0-canary-d2908752-20260119) - '@radix-ui/react-slot': 1.2.3(@types/react@19.2.2)(react@19.3.0-canary-d2908752-20260119) - '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@19.2.2)(react@19.3.0-canary-d2908752-20260119) + '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.2)(react@19.3.0-canary-b546603b-20260121) + '@radix-ui/react-context': 1.1.2(@types/react@19.2.2)(react@19.3.0-canary-b546603b-20260121) + '@radix-ui/react-dismissable-layer': 1.1.11(@types/react-dom@19.2.1(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.3.0-canary-b546603b-20260121(react@19.3.0-canary-b546603b-20260121))(react@19.3.0-canary-b546603b-20260121) + '@radix-ui/react-focus-guards': 1.1.3(@types/react@19.2.2)(react@19.3.0-canary-b546603b-20260121) + '@radix-ui/react-focus-scope': 1.1.7(@types/react-dom@19.2.1(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.3.0-canary-b546603b-20260121(react@19.3.0-canary-b546603b-20260121))(react@19.3.0-canary-b546603b-20260121) + '@radix-ui/react-id': 1.1.1(@types/react@19.2.2)(react@19.3.0-canary-b546603b-20260121) + '@radix-ui/react-portal': 1.1.9(@types/react-dom@19.2.1(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.3.0-canary-b546603b-20260121(react@19.3.0-canary-b546603b-20260121))(react@19.3.0-canary-b546603b-20260121) + '@radix-ui/react-presence': 1.1.5(@types/react-dom@19.2.1(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.3.0-canary-b546603b-20260121(react@19.3.0-canary-b546603b-20260121))(react@19.3.0-canary-b546603b-20260121) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.1(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.3.0-canary-b546603b-20260121(react@19.3.0-canary-b546603b-20260121))(react@19.3.0-canary-b546603b-20260121) + '@radix-ui/react-slot': 1.2.3(@types/react@19.2.2)(react@19.3.0-canary-b546603b-20260121) + '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@19.2.2)(react@19.3.0-canary-b546603b-20260121) aria-hidden: 1.2.6 - react: 19.3.0-canary-d2908752-20260119 - react-dom: 19.3.0-canary-d2908752-20260119(react@19.3.0-canary-d2908752-20260119) - react-remove-scroll: 2.7.1(@types/react@19.2.2)(react@19.3.0-canary-d2908752-20260119) + react: 19.3.0-canary-b546603b-20260121 + react-dom: 19.3.0-canary-b546603b-20260121(react@19.3.0-canary-b546603b-20260121) + react-remove-scroll: 2.7.1(@types/react@19.2.2)(react@19.3.0-canary-b546603b-20260121) optionalDependencies: '@types/react': 19.2.2 '@types/react-dom': 19.2.1(@types/react@19.2.2) - '@radix-ui/react-dialog@1.1.4(@types/react-dom@19.2.1(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.3.0-canary-d2908752-20260119(react@19.3.0-canary-d2908752-20260119))(react@19.3.0-canary-d2908752-20260119)': + '@radix-ui/react-dialog@1.1.4(@types/react-dom@19.2.1(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.3.0-canary-b546603b-20260121(react@19.3.0-canary-b546603b-20260121))(react@19.3.0-canary-b546603b-20260121)': dependencies: '@radix-ui/primitive': 1.1.1 - '@radix-ui/react-compose-refs': 1.1.1(@types/react@19.2.2)(react@19.3.0-canary-d2908752-20260119) - '@radix-ui/react-context': 1.1.1(@types/react@19.2.2)(react@19.3.0-canary-d2908752-20260119) - '@radix-ui/react-dismissable-layer': 1.1.3(@types/react-dom@19.2.1(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.3.0-canary-d2908752-20260119(react@19.3.0-canary-d2908752-20260119))(react@19.3.0-canary-d2908752-20260119) - '@radix-ui/react-focus-guards': 1.1.1(@types/react@19.2.2)(react@19.3.0-canary-d2908752-20260119) - '@radix-ui/react-focus-scope': 1.1.1(@types/react-dom@19.2.1(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.3.0-canary-d2908752-20260119(react@19.3.0-canary-d2908752-20260119))(react@19.3.0-canary-d2908752-20260119) - '@radix-ui/react-id': 1.1.0(@types/react@19.2.2)(react@19.3.0-canary-d2908752-20260119) - '@radix-ui/react-portal': 1.1.3(@types/react-dom@19.2.1(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.3.0-canary-d2908752-20260119(react@19.3.0-canary-d2908752-20260119))(react@19.3.0-canary-d2908752-20260119) - '@radix-ui/react-presence': 1.1.2(@types/react-dom@19.2.1(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.3.0-canary-d2908752-20260119(react@19.3.0-canary-d2908752-20260119))(react@19.3.0-canary-d2908752-20260119) - '@radix-ui/react-primitive': 2.0.1(@types/react-dom@19.2.1(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.3.0-canary-d2908752-20260119(react@19.3.0-canary-d2908752-20260119))(react@19.3.0-canary-d2908752-20260119) - '@radix-ui/react-slot': 1.1.1(@types/react@19.2.2)(react@19.3.0-canary-d2908752-20260119) - '@radix-ui/react-use-controllable-state': 1.1.0(@types/react@19.2.2)(react@19.3.0-canary-d2908752-20260119) + '@radix-ui/react-compose-refs': 1.1.1(@types/react@19.2.2)(react@19.3.0-canary-b546603b-20260121) + '@radix-ui/react-context': 1.1.1(@types/react@19.2.2)(react@19.3.0-canary-b546603b-20260121) + '@radix-ui/react-dismissable-layer': 1.1.3(@types/react-dom@19.2.1(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.3.0-canary-b546603b-20260121(react@19.3.0-canary-b546603b-20260121))(react@19.3.0-canary-b546603b-20260121) + '@radix-ui/react-focus-guards': 1.1.1(@types/react@19.2.2)(react@19.3.0-canary-b546603b-20260121) + '@radix-ui/react-focus-scope': 1.1.1(@types/react-dom@19.2.1(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.3.0-canary-b546603b-20260121(react@19.3.0-canary-b546603b-20260121))(react@19.3.0-canary-b546603b-20260121) + '@radix-ui/react-id': 1.1.0(@types/react@19.2.2)(react@19.3.0-canary-b546603b-20260121) + '@radix-ui/react-portal': 1.1.3(@types/react-dom@19.2.1(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.3.0-canary-b546603b-20260121(react@19.3.0-canary-b546603b-20260121))(react@19.3.0-canary-b546603b-20260121) + '@radix-ui/react-presence': 1.1.2(@types/react-dom@19.2.1(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.3.0-canary-b546603b-20260121(react@19.3.0-canary-b546603b-20260121))(react@19.3.0-canary-b546603b-20260121) + '@radix-ui/react-primitive': 2.0.1(@types/react-dom@19.2.1(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.3.0-canary-b546603b-20260121(react@19.3.0-canary-b546603b-20260121))(react@19.3.0-canary-b546603b-20260121) + '@radix-ui/react-slot': 1.1.1(@types/react@19.2.2)(react@19.3.0-canary-b546603b-20260121) + '@radix-ui/react-use-controllable-state': 1.1.0(@types/react@19.2.2)(react@19.3.0-canary-b546603b-20260121) aria-hidden: 1.2.6 - react: 19.3.0-canary-d2908752-20260119 - react-dom: 19.3.0-canary-d2908752-20260119(react@19.3.0-canary-d2908752-20260119) - react-remove-scroll: 2.7.1(@types/react@19.2.2)(react@19.3.0-canary-d2908752-20260119) + react: 19.3.0-canary-b546603b-20260121 + react-dom: 19.3.0-canary-b546603b-20260121(react@19.3.0-canary-b546603b-20260121) + react-remove-scroll: 2.7.1(@types/react@19.2.2)(react@19.3.0-canary-b546603b-20260121) optionalDependencies: '@types/react': 19.2.2 '@types/react-dom': 19.2.1(@types/react@19.2.2) - '@radix-ui/react-direction@1.1.0(@types/react@19.2.2)(react@19.3.0-canary-d2908752-20260119)': + '@radix-ui/react-direction@1.1.0(@types/react@19.2.2)(react@19.3.0-canary-b546603b-20260121)': dependencies: - react: 19.3.0-canary-d2908752-20260119 + react: 19.3.0-canary-b546603b-20260121 optionalDependencies: '@types/react': 19.2.2 - '@radix-ui/react-direction@1.1.1(@types/react@19.2.2)(react@19.3.0-canary-d2908752-20260119)': + '@radix-ui/react-direction@1.1.1(@types/react@19.2.2)(react@19.3.0-canary-b546603b-20260121)': dependencies: - react: 19.3.0-canary-d2908752-20260119 + react: 19.3.0-canary-b546603b-20260121 optionalDependencies: '@types/react': 19.2.2 - '@radix-ui/react-dismissable-layer@1.1.1(@types/react-dom@19.2.1(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.3.0-canary-d2908752-20260119(react@19.3.0-canary-d2908752-20260119))(react@19.3.0-canary-d2908752-20260119)': + '@radix-ui/react-dismissable-layer@1.1.1(@types/react-dom@19.2.1(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.3.0-canary-b546603b-20260121(react@19.3.0-canary-b546603b-20260121))(react@19.3.0-canary-b546603b-20260121)': dependencies: '@radix-ui/primitive': 1.1.0 - '@radix-ui/react-compose-refs': 1.1.0(@types/react@19.2.2)(react@19.3.0-canary-d2908752-20260119) - '@radix-ui/react-primitive': 2.0.0(@types/react-dom@19.2.1(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.3.0-canary-d2908752-20260119(react@19.3.0-canary-d2908752-20260119))(react@19.3.0-canary-d2908752-20260119) - '@radix-ui/react-use-callback-ref': 1.1.0(@types/react@19.2.2)(react@19.3.0-canary-d2908752-20260119) - '@radix-ui/react-use-escape-keydown': 1.1.0(@types/react@19.2.2)(react@19.3.0-canary-d2908752-20260119) - react: 19.3.0-canary-d2908752-20260119 - react-dom: 19.3.0-canary-d2908752-20260119(react@19.3.0-canary-d2908752-20260119) + '@radix-ui/react-compose-refs': 1.1.0(@types/react@19.2.2)(react@19.3.0-canary-b546603b-20260121) + '@radix-ui/react-primitive': 2.0.0(@types/react-dom@19.2.1(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.3.0-canary-b546603b-20260121(react@19.3.0-canary-b546603b-20260121))(react@19.3.0-canary-b546603b-20260121) + '@radix-ui/react-use-callback-ref': 1.1.0(@types/react@19.2.2)(react@19.3.0-canary-b546603b-20260121) + '@radix-ui/react-use-escape-keydown': 1.1.0(@types/react@19.2.2)(react@19.3.0-canary-b546603b-20260121) + react: 19.3.0-canary-b546603b-20260121 + react-dom: 19.3.0-canary-b546603b-20260121(react@19.3.0-canary-b546603b-20260121) optionalDependencies: '@types/react': 19.2.2 '@types/react-dom': 19.2.1(@types/react@19.2.2) - '@radix-ui/react-dismissable-layer@1.1.11(@types/react-dom@19.2.1(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.3.0-canary-d2908752-20260119(react@19.3.0-canary-d2908752-20260119))(react@19.3.0-canary-d2908752-20260119)': + '@radix-ui/react-dismissable-layer@1.1.11(@types/react-dom@19.2.1(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.3.0-canary-b546603b-20260121(react@19.3.0-canary-b546603b-20260121))(react@19.3.0-canary-b546603b-20260121)': dependencies: '@radix-ui/primitive': 1.1.3 - '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.2)(react@19.3.0-canary-d2908752-20260119) - '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.1(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.3.0-canary-d2908752-20260119(react@19.3.0-canary-d2908752-20260119))(react@19.3.0-canary-d2908752-20260119) - '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@19.2.2)(react@19.3.0-canary-d2908752-20260119) - '@radix-ui/react-use-escape-keydown': 1.1.1(@types/react@19.2.2)(react@19.3.0-canary-d2908752-20260119) - react: 19.3.0-canary-d2908752-20260119 - react-dom: 19.3.0-canary-d2908752-20260119(react@19.3.0-canary-d2908752-20260119) + '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.2)(react@19.3.0-canary-b546603b-20260121) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.1(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.3.0-canary-b546603b-20260121(react@19.3.0-canary-b546603b-20260121))(react@19.3.0-canary-b546603b-20260121) + '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@19.2.2)(react@19.3.0-canary-b546603b-20260121) + '@radix-ui/react-use-escape-keydown': 1.1.1(@types/react@19.2.2)(react@19.3.0-canary-b546603b-20260121) + react: 19.3.0-canary-b546603b-20260121 + react-dom: 19.3.0-canary-b546603b-20260121(react@19.3.0-canary-b546603b-20260121) optionalDependencies: '@types/react': 19.2.2 '@types/react-dom': 19.2.1(@types/react@19.2.2) - '@radix-ui/react-dismissable-layer@1.1.3(@types/react-dom@19.2.1(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.3.0-canary-d2908752-20260119(react@19.3.0-canary-d2908752-20260119))(react@19.3.0-canary-d2908752-20260119)': + '@radix-ui/react-dismissable-layer@1.1.3(@types/react-dom@19.2.1(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.3.0-canary-b546603b-20260121(react@19.3.0-canary-b546603b-20260121))(react@19.3.0-canary-b546603b-20260121)': dependencies: '@radix-ui/primitive': 1.1.1 - '@radix-ui/react-compose-refs': 1.1.1(@types/react@19.2.2)(react@19.3.0-canary-d2908752-20260119) - '@radix-ui/react-primitive': 2.0.1(@types/react-dom@19.2.1(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.3.0-canary-d2908752-20260119(react@19.3.0-canary-d2908752-20260119))(react@19.3.0-canary-d2908752-20260119) - '@radix-ui/react-use-callback-ref': 1.1.0(@types/react@19.2.2)(react@19.3.0-canary-d2908752-20260119) - '@radix-ui/react-use-escape-keydown': 1.1.0(@types/react@19.2.2)(react@19.3.0-canary-d2908752-20260119) - react: 19.3.0-canary-d2908752-20260119 - react-dom: 19.3.0-canary-d2908752-20260119(react@19.3.0-canary-d2908752-20260119) + '@radix-ui/react-compose-refs': 1.1.1(@types/react@19.2.2)(react@19.3.0-canary-b546603b-20260121) + '@radix-ui/react-primitive': 2.0.1(@types/react-dom@19.2.1(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.3.0-canary-b546603b-20260121(react@19.3.0-canary-b546603b-20260121))(react@19.3.0-canary-b546603b-20260121) + '@radix-ui/react-use-callback-ref': 1.1.0(@types/react@19.2.2)(react@19.3.0-canary-b546603b-20260121) + '@radix-ui/react-use-escape-keydown': 1.1.0(@types/react@19.2.2)(react@19.3.0-canary-b546603b-20260121) + react: 19.3.0-canary-b546603b-20260121 + react-dom: 19.3.0-canary-b546603b-20260121(react@19.3.0-canary-b546603b-20260121) optionalDependencies: '@types/react': 19.2.2 '@types/react-dom': 19.2.1(@types/react@19.2.2) - '@radix-ui/react-focus-guards@1.1.1(@types/react@19.2.2)(react@19.3.0-canary-d2908752-20260119)': + '@radix-ui/react-focus-guards@1.1.1(@types/react@19.2.2)(react@19.3.0-canary-b546603b-20260121)': dependencies: - react: 19.3.0-canary-d2908752-20260119 + react: 19.3.0-canary-b546603b-20260121 optionalDependencies: '@types/react': 19.2.2 - '@radix-ui/react-focus-guards@1.1.3(@types/react@19.2.2)(react@19.3.0-canary-d2908752-20260119)': + '@radix-ui/react-focus-guards@1.1.3(@types/react@19.2.2)(react@19.3.0-canary-b546603b-20260121)': dependencies: - react: 19.3.0-canary-d2908752-20260119 + react: 19.3.0-canary-b546603b-20260121 optionalDependencies: '@types/react': 19.2.2 - '@radix-ui/react-focus-scope@1.1.1(@types/react-dom@19.2.1(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.3.0-canary-d2908752-20260119(react@19.3.0-canary-d2908752-20260119))(react@19.3.0-canary-d2908752-20260119)': + '@radix-ui/react-focus-scope@1.1.1(@types/react-dom@19.2.1(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.3.0-canary-b546603b-20260121(react@19.3.0-canary-b546603b-20260121))(react@19.3.0-canary-b546603b-20260121)': dependencies: - '@radix-ui/react-compose-refs': 1.1.1(@types/react@19.2.2)(react@19.3.0-canary-d2908752-20260119) - '@radix-ui/react-primitive': 2.0.1(@types/react-dom@19.2.1(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.3.0-canary-d2908752-20260119(react@19.3.0-canary-d2908752-20260119))(react@19.3.0-canary-d2908752-20260119) - '@radix-ui/react-use-callback-ref': 1.1.0(@types/react@19.2.2)(react@19.3.0-canary-d2908752-20260119) - react: 19.3.0-canary-d2908752-20260119 - react-dom: 19.3.0-canary-d2908752-20260119(react@19.3.0-canary-d2908752-20260119) + '@radix-ui/react-compose-refs': 1.1.1(@types/react@19.2.2)(react@19.3.0-canary-b546603b-20260121) + '@radix-ui/react-primitive': 2.0.1(@types/react-dom@19.2.1(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.3.0-canary-b546603b-20260121(react@19.3.0-canary-b546603b-20260121))(react@19.3.0-canary-b546603b-20260121) + '@radix-ui/react-use-callback-ref': 1.1.0(@types/react@19.2.2)(react@19.3.0-canary-b546603b-20260121) + react: 19.3.0-canary-b546603b-20260121 + react-dom: 19.3.0-canary-b546603b-20260121(react@19.3.0-canary-b546603b-20260121) optionalDependencies: '@types/react': 19.2.2 '@types/react-dom': 19.2.1(@types/react@19.2.2) - '@radix-ui/react-focus-scope@1.1.7(@types/react-dom@19.2.1(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.3.0-canary-d2908752-20260119(react@19.3.0-canary-d2908752-20260119))(react@19.3.0-canary-d2908752-20260119)': + '@radix-ui/react-focus-scope@1.1.7(@types/react-dom@19.2.1(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.3.0-canary-b546603b-20260121(react@19.3.0-canary-b546603b-20260121))(react@19.3.0-canary-b546603b-20260121)': dependencies: - '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.2)(react@19.3.0-canary-d2908752-20260119) - '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.1(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.3.0-canary-d2908752-20260119(react@19.3.0-canary-d2908752-20260119))(react@19.3.0-canary-d2908752-20260119) - '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@19.2.2)(react@19.3.0-canary-d2908752-20260119) - react: 19.3.0-canary-d2908752-20260119 - react-dom: 19.3.0-canary-d2908752-20260119(react@19.3.0-canary-d2908752-20260119) + '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.2)(react@19.3.0-canary-b546603b-20260121) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.1(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.3.0-canary-b546603b-20260121(react@19.3.0-canary-b546603b-20260121))(react@19.3.0-canary-b546603b-20260121) + '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@19.2.2)(react@19.3.0-canary-b546603b-20260121) + react: 19.3.0-canary-b546603b-20260121 + react-dom: 19.3.0-canary-b546603b-20260121(react@19.3.0-canary-b546603b-20260121) optionalDependencies: '@types/react': 19.2.2 '@types/react-dom': 19.2.1(@types/react@19.2.2) - '@radix-ui/react-id@1.1.0(@types/react@19.2.2)(react@19.3.0-canary-d2908752-20260119)': + '@radix-ui/react-id@1.1.0(@types/react@19.2.2)(react@19.3.0-canary-b546603b-20260121)': dependencies: - '@radix-ui/react-use-layout-effect': 1.1.0(@types/react@19.2.2)(react@19.3.0-canary-d2908752-20260119) - react: 19.3.0-canary-d2908752-20260119 + '@radix-ui/react-use-layout-effect': 1.1.0(@types/react@19.2.2)(react@19.3.0-canary-b546603b-20260121) + react: 19.3.0-canary-b546603b-20260121 optionalDependencies: '@types/react': 19.2.2 - '@radix-ui/react-id@1.1.1(@types/react@19.2.2)(react@19.3.0-canary-d2908752-20260119)': + '@radix-ui/react-id@1.1.1(@types/react@19.2.2)(react@19.3.0-canary-b546603b-20260121)': dependencies: - '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.2.2)(react@19.3.0-canary-d2908752-20260119) - react: 19.3.0-canary-d2908752-20260119 + '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.2.2)(react@19.3.0-canary-b546603b-20260121) + react: 19.3.0-canary-b546603b-20260121 optionalDependencies: '@types/react': 19.2.2 - '@radix-ui/react-navigation-menu@1.2.14(@types/react-dom@19.2.1(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.3.0-canary-d2908752-20260119(react@19.3.0-canary-d2908752-20260119))(react@19.3.0-canary-d2908752-20260119)': + '@radix-ui/react-navigation-menu@1.2.14(@types/react-dom@19.2.1(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.3.0-canary-b546603b-20260121(react@19.3.0-canary-b546603b-20260121))(react@19.3.0-canary-b546603b-20260121)': dependencies: '@radix-ui/primitive': 1.1.3 - '@radix-ui/react-collection': 1.1.7(@types/react-dom@19.2.1(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.3.0-canary-d2908752-20260119(react@19.3.0-canary-d2908752-20260119))(react@19.3.0-canary-d2908752-20260119) - '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.2)(react@19.3.0-canary-d2908752-20260119) - '@radix-ui/react-context': 1.1.2(@types/react@19.2.2)(react@19.3.0-canary-d2908752-20260119) - '@radix-ui/react-direction': 1.1.1(@types/react@19.2.2)(react@19.3.0-canary-d2908752-20260119) - '@radix-ui/react-dismissable-layer': 1.1.11(@types/react-dom@19.2.1(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.3.0-canary-d2908752-20260119(react@19.3.0-canary-d2908752-20260119))(react@19.3.0-canary-d2908752-20260119) - '@radix-ui/react-id': 1.1.1(@types/react@19.2.2)(react@19.3.0-canary-d2908752-20260119) - '@radix-ui/react-presence': 1.1.5(@types/react-dom@19.2.1(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.3.0-canary-d2908752-20260119(react@19.3.0-canary-d2908752-20260119))(react@19.3.0-canary-d2908752-20260119) - '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.1(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.3.0-canary-d2908752-20260119(react@19.3.0-canary-d2908752-20260119))(react@19.3.0-canary-d2908752-20260119) - '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@19.2.2)(react@19.3.0-canary-d2908752-20260119) - '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@19.2.2)(react@19.3.0-canary-d2908752-20260119) - '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.2.2)(react@19.3.0-canary-d2908752-20260119) - '@radix-ui/react-use-previous': 1.1.1(@types/react@19.2.2)(react@19.3.0-canary-d2908752-20260119) - '@radix-ui/react-visually-hidden': 1.2.3(@types/react-dom@19.2.1(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.3.0-canary-d2908752-20260119(react@19.3.0-canary-d2908752-20260119))(react@19.3.0-canary-d2908752-20260119) - react: 19.3.0-canary-d2908752-20260119 - react-dom: 19.3.0-canary-d2908752-20260119(react@19.3.0-canary-d2908752-20260119) + '@radix-ui/react-collection': 1.1.7(@types/react-dom@19.2.1(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.3.0-canary-b546603b-20260121(react@19.3.0-canary-b546603b-20260121))(react@19.3.0-canary-b546603b-20260121) + '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.2)(react@19.3.0-canary-b546603b-20260121) + '@radix-ui/react-context': 1.1.2(@types/react@19.2.2)(react@19.3.0-canary-b546603b-20260121) + '@radix-ui/react-direction': 1.1.1(@types/react@19.2.2)(react@19.3.0-canary-b546603b-20260121) + '@radix-ui/react-dismissable-layer': 1.1.11(@types/react-dom@19.2.1(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.3.0-canary-b546603b-20260121(react@19.3.0-canary-b546603b-20260121))(react@19.3.0-canary-b546603b-20260121) + '@radix-ui/react-id': 1.1.1(@types/react@19.2.2)(react@19.3.0-canary-b546603b-20260121) + '@radix-ui/react-presence': 1.1.5(@types/react-dom@19.2.1(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.3.0-canary-b546603b-20260121(react@19.3.0-canary-b546603b-20260121))(react@19.3.0-canary-b546603b-20260121) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.1(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.3.0-canary-b546603b-20260121(react@19.3.0-canary-b546603b-20260121))(react@19.3.0-canary-b546603b-20260121) + '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@19.2.2)(react@19.3.0-canary-b546603b-20260121) + '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@19.2.2)(react@19.3.0-canary-b546603b-20260121) + '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.2.2)(react@19.3.0-canary-b546603b-20260121) + '@radix-ui/react-use-previous': 1.1.1(@types/react@19.2.2)(react@19.3.0-canary-b546603b-20260121) + '@radix-ui/react-visually-hidden': 1.2.3(@types/react-dom@19.2.1(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.3.0-canary-b546603b-20260121(react@19.3.0-canary-b546603b-20260121))(react@19.3.0-canary-b546603b-20260121) + react: 19.3.0-canary-b546603b-20260121 + react-dom: 19.3.0-canary-b546603b-20260121(react@19.3.0-canary-b546603b-20260121) optionalDependencies: '@types/react': 19.2.2 '@types/react-dom': 19.2.1(@types/react@19.2.2) - '@radix-ui/react-popover@1.1.15(@types/react-dom@19.2.1(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.3.0-canary-d2908752-20260119(react@19.3.0-canary-d2908752-20260119))(react@19.3.0-canary-d2908752-20260119)': + '@radix-ui/react-popover@1.1.15(@types/react-dom@19.2.1(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.3.0-canary-b546603b-20260121(react@19.3.0-canary-b546603b-20260121))(react@19.3.0-canary-b546603b-20260121)': dependencies: '@radix-ui/primitive': 1.1.3 - '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.2)(react@19.3.0-canary-d2908752-20260119) - '@radix-ui/react-context': 1.1.2(@types/react@19.2.2)(react@19.3.0-canary-d2908752-20260119) - '@radix-ui/react-dismissable-layer': 1.1.11(@types/react-dom@19.2.1(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.3.0-canary-d2908752-20260119(react@19.3.0-canary-d2908752-20260119))(react@19.3.0-canary-d2908752-20260119) - '@radix-ui/react-focus-guards': 1.1.3(@types/react@19.2.2)(react@19.3.0-canary-d2908752-20260119) - '@radix-ui/react-focus-scope': 1.1.7(@types/react-dom@19.2.1(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.3.0-canary-d2908752-20260119(react@19.3.0-canary-d2908752-20260119))(react@19.3.0-canary-d2908752-20260119) - '@radix-ui/react-id': 1.1.1(@types/react@19.2.2)(react@19.3.0-canary-d2908752-20260119) - '@radix-ui/react-popper': 1.2.8(@types/react-dom@19.2.1(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.3.0-canary-d2908752-20260119(react@19.3.0-canary-d2908752-20260119))(react@19.3.0-canary-d2908752-20260119) - '@radix-ui/react-portal': 1.1.9(@types/react-dom@19.2.1(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.3.0-canary-d2908752-20260119(react@19.3.0-canary-d2908752-20260119))(react@19.3.0-canary-d2908752-20260119) - '@radix-ui/react-presence': 1.1.5(@types/react-dom@19.2.1(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.3.0-canary-d2908752-20260119(react@19.3.0-canary-d2908752-20260119))(react@19.3.0-canary-d2908752-20260119) - '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.1(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.3.0-canary-d2908752-20260119(react@19.3.0-canary-d2908752-20260119))(react@19.3.0-canary-d2908752-20260119) - '@radix-ui/react-slot': 1.2.3(@types/react@19.2.2)(react@19.3.0-canary-d2908752-20260119) - '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@19.2.2)(react@19.3.0-canary-d2908752-20260119) + '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.2)(react@19.3.0-canary-b546603b-20260121) + '@radix-ui/react-context': 1.1.2(@types/react@19.2.2)(react@19.3.0-canary-b546603b-20260121) + '@radix-ui/react-dismissable-layer': 1.1.11(@types/react-dom@19.2.1(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.3.0-canary-b546603b-20260121(react@19.3.0-canary-b546603b-20260121))(react@19.3.0-canary-b546603b-20260121) + '@radix-ui/react-focus-guards': 1.1.3(@types/react@19.2.2)(react@19.3.0-canary-b546603b-20260121) + '@radix-ui/react-focus-scope': 1.1.7(@types/react-dom@19.2.1(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.3.0-canary-b546603b-20260121(react@19.3.0-canary-b546603b-20260121))(react@19.3.0-canary-b546603b-20260121) + '@radix-ui/react-id': 1.1.1(@types/react@19.2.2)(react@19.3.0-canary-b546603b-20260121) + '@radix-ui/react-popper': 1.2.8(@types/react-dom@19.2.1(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.3.0-canary-b546603b-20260121(react@19.3.0-canary-b546603b-20260121))(react@19.3.0-canary-b546603b-20260121) + '@radix-ui/react-portal': 1.1.9(@types/react-dom@19.2.1(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.3.0-canary-b546603b-20260121(react@19.3.0-canary-b546603b-20260121))(react@19.3.0-canary-b546603b-20260121) + '@radix-ui/react-presence': 1.1.5(@types/react-dom@19.2.1(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.3.0-canary-b546603b-20260121(react@19.3.0-canary-b546603b-20260121))(react@19.3.0-canary-b546603b-20260121) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.1(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.3.0-canary-b546603b-20260121(react@19.3.0-canary-b546603b-20260121))(react@19.3.0-canary-b546603b-20260121) + '@radix-ui/react-slot': 1.2.3(@types/react@19.2.2)(react@19.3.0-canary-b546603b-20260121) + '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@19.2.2)(react@19.3.0-canary-b546603b-20260121) aria-hidden: 1.2.6 - react: 19.3.0-canary-d2908752-20260119 - react-dom: 19.3.0-canary-d2908752-20260119(react@19.3.0-canary-d2908752-20260119) - react-remove-scroll: 2.7.1(@types/react@19.2.2)(react@19.3.0-canary-d2908752-20260119) + react: 19.3.0-canary-b546603b-20260121 + react-dom: 19.3.0-canary-b546603b-20260121(react@19.3.0-canary-b546603b-20260121) + react-remove-scroll: 2.7.1(@types/react@19.2.2)(react@19.3.0-canary-b546603b-20260121) optionalDependencies: '@types/react': 19.2.2 '@types/react-dom': 19.2.1(@types/react@19.2.2) - '@radix-ui/react-popover@1.1.4(@types/react-dom@19.2.1(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.3.0-canary-d2908752-20260119(react@19.3.0-canary-d2908752-20260119))(react@19.3.0-canary-d2908752-20260119)': + '@radix-ui/react-popover@1.1.4(@types/react-dom@19.2.1(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.3.0-canary-b546603b-20260121(react@19.3.0-canary-b546603b-20260121))(react@19.3.0-canary-b546603b-20260121)': dependencies: '@radix-ui/primitive': 1.1.1 - '@radix-ui/react-compose-refs': 1.1.1(@types/react@19.2.2)(react@19.3.0-canary-d2908752-20260119) - '@radix-ui/react-context': 1.1.1(@types/react@19.2.2)(react@19.3.0-canary-d2908752-20260119) - '@radix-ui/react-dismissable-layer': 1.1.3(@types/react-dom@19.2.1(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.3.0-canary-d2908752-20260119(react@19.3.0-canary-d2908752-20260119))(react@19.3.0-canary-d2908752-20260119) - '@radix-ui/react-focus-guards': 1.1.1(@types/react@19.2.2)(react@19.3.0-canary-d2908752-20260119) - '@radix-ui/react-focus-scope': 1.1.1(@types/react-dom@19.2.1(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.3.0-canary-d2908752-20260119(react@19.3.0-canary-d2908752-20260119))(react@19.3.0-canary-d2908752-20260119) - '@radix-ui/react-id': 1.1.0(@types/react@19.2.2)(react@19.3.0-canary-d2908752-20260119) - '@radix-ui/react-popper': 1.2.1(@types/react-dom@19.2.1(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.3.0-canary-d2908752-20260119(react@19.3.0-canary-d2908752-20260119))(react@19.3.0-canary-d2908752-20260119) - '@radix-ui/react-portal': 1.1.3(@types/react-dom@19.2.1(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.3.0-canary-d2908752-20260119(react@19.3.0-canary-d2908752-20260119))(react@19.3.0-canary-d2908752-20260119) - '@radix-ui/react-presence': 1.1.2(@types/react-dom@19.2.1(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.3.0-canary-d2908752-20260119(react@19.3.0-canary-d2908752-20260119))(react@19.3.0-canary-d2908752-20260119) - '@radix-ui/react-primitive': 2.0.1(@types/react-dom@19.2.1(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.3.0-canary-d2908752-20260119(react@19.3.0-canary-d2908752-20260119))(react@19.3.0-canary-d2908752-20260119) - '@radix-ui/react-slot': 1.1.1(@types/react@19.2.2)(react@19.3.0-canary-d2908752-20260119) - '@radix-ui/react-use-controllable-state': 1.1.0(@types/react@19.2.2)(react@19.3.0-canary-d2908752-20260119) + '@radix-ui/react-compose-refs': 1.1.1(@types/react@19.2.2)(react@19.3.0-canary-b546603b-20260121) + '@radix-ui/react-context': 1.1.1(@types/react@19.2.2)(react@19.3.0-canary-b546603b-20260121) + '@radix-ui/react-dismissable-layer': 1.1.3(@types/react-dom@19.2.1(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.3.0-canary-b546603b-20260121(react@19.3.0-canary-b546603b-20260121))(react@19.3.0-canary-b546603b-20260121) + '@radix-ui/react-focus-guards': 1.1.1(@types/react@19.2.2)(react@19.3.0-canary-b546603b-20260121) + '@radix-ui/react-focus-scope': 1.1.1(@types/react-dom@19.2.1(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.3.0-canary-b546603b-20260121(react@19.3.0-canary-b546603b-20260121))(react@19.3.0-canary-b546603b-20260121) + '@radix-ui/react-id': 1.1.0(@types/react@19.2.2)(react@19.3.0-canary-b546603b-20260121) + '@radix-ui/react-popper': 1.2.1(@types/react-dom@19.2.1(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.3.0-canary-b546603b-20260121(react@19.3.0-canary-b546603b-20260121))(react@19.3.0-canary-b546603b-20260121) + '@radix-ui/react-portal': 1.1.3(@types/react-dom@19.2.1(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.3.0-canary-b546603b-20260121(react@19.3.0-canary-b546603b-20260121))(react@19.3.0-canary-b546603b-20260121) + '@radix-ui/react-presence': 1.1.2(@types/react-dom@19.2.1(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.3.0-canary-b546603b-20260121(react@19.3.0-canary-b546603b-20260121))(react@19.3.0-canary-b546603b-20260121) + '@radix-ui/react-primitive': 2.0.1(@types/react-dom@19.2.1(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.3.0-canary-b546603b-20260121(react@19.3.0-canary-b546603b-20260121))(react@19.3.0-canary-b546603b-20260121) + '@radix-ui/react-slot': 1.1.1(@types/react@19.2.2)(react@19.3.0-canary-b546603b-20260121) + '@radix-ui/react-use-controllable-state': 1.1.0(@types/react@19.2.2)(react@19.3.0-canary-b546603b-20260121) aria-hidden: 1.2.6 - react: 19.3.0-canary-d2908752-20260119 - react-dom: 19.3.0-canary-d2908752-20260119(react@19.3.0-canary-d2908752-20260119) - react-remove-scroll: 2.7.1(@types/react@19.2.2)(react@19.3.0-canary-d2908752-20260119) + react: 19.3.0-canary-b546603b-20260121 + react-dom: 19.3.0-canary-b546603b-20260121(react@19.3.0-canary-b546603b-20260121) + react-remove-scroll: 2.7.1(@types/react@19.2.2)(react@19.3.0-canary-b546603b-20260121) optionalDependencies: '@types/react': 19.2.2 '@types/react-dom': 19.2.1(@types/react@19.2.2) - '@radix-ui/react-popper@1.2.0(@types/react-dom@19.2.1(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.3.0-canary-d2908752-20260119(react@19.3.0-canary-d2908752-20260119))(react@19.3.0-canary-d2908752-20260119)': - dependencies: - '@floating-ui/react-dom': 2.1.5(react-dom@19.3.0-canary-d2908752-20260119(react@19.3.0-canary-d2908752-20260119))(react@19.3.0-canary-d2908752-20260119) - '@radix-ui/react-arrow': 1.1.0(@types/react-dom@19.2.1(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.3.0-canary-d2908752-20260119(react@19.3.0-canary-d2908752-20260119))(react@19.3.0-canary-d2908752-20260119) - '@radix-ui/react-compose-refs': 1.1.0(@types/react@19.2.2)(react@19.3.0-canary-d2908752-20260119) - '@radix-ui/react-context': 1.1.0(@types/react@19.2.2)(react@19.3.0-canary-d2908752-20260119) - '@radix-ui/react-primitive': 2.0.0(@types/react-dom@19.2.1(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.3.0-canary-d2908752-20260119(react@19.3.0-canary-d2908752-20260119))(react@19.3.0-canary-d2908752-20260119) - '@radix-ui/react-use-callback-ref': 1.1.0(@types/react@19.2.2)(react@19.3.0-canary-d2908752-20260119) - '@radix-ui/react-use-layout-effect': 1.1.0(@types/react@19.2.2)(react@19.3.0-canary-d2908752-20260119) - '@radix-ui/react-use-rect': 1.1.0(@types/react@19.2.2)(react@19.3.0-canary-d2908752-20260119) - '@radix-ui/react-use-size': 1.1.0(@types/react@19.2.2)(react@19.3.0-canary-d2908752-20260119) + '@radix-ui/react-popper@1.2.0(@types/react-dom@19.2.1(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.3.0-canary-b546603b-20260121(react@19.3.0-canary-b546603b-20260121))(react@19.3.0-canary-b546603b-20260121)': + dependencies: + '@floating-ui/react-dom': 2.1.5(react-dom@19.3.0-canary-b546603b-20260121(react@19.3.0-canary-b546603b-20260121))(react@19.3.0-canary-b546603b-20260121) + '@radix-ui/react-arrow': 1.1.0(@types/react-dom@19.2.1(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.3.0-canary-b546603b-20260121(react@19.3.0-canary-b546603b-20260121))(react@19.3.0-canary-b546603b-20260121) + '@radix-ui/react-compose-refs': 1.1.0(@types/react@19.2.2)(react@19.3.0-canary-b546603b-20260121) + '@radix-ui/react-context': 1.1.0(@types/react@19.2.2)(react@19.3.0-canary-b546603b-20260121) + '@radix-ui/react-primitive': 2.0.0(@types/react-dom@19.2.1(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.3.0-canary-b546603b-20260121(react@19.3.0-canary-b546603b-20260121))(react@19.3.0-canary-b546603b-20260121) + '@radix-ui/react-use-callback-ref': 1.1.0(@types/react@19.2.2)(react@19.3.0-canary-b546603b-20260121) + '@radix-ui/react-use-layout-effect': 1.1.0(@types/react@19.2.2)(react@19.3.0-canary-b546603b-20260121) + '@radix-ui/react-use-rect': 1.1.0(@types/react@19.2.2)(react@19.3.0-canary-b546603b-20260121) + '@radix-ui/react-use-size': 1.1.0(@types/react@19.2.2)(react@19.3.0-canary-b546603b-20260121) '@radix-ui/rect': 1.1.0 - react: 19.3.0-canary-d2908752-20260119 - react-dom: 19.3.0-canary-d2908752-20260119(react@19.3.0-canary-d2908752-20260119) + react: 19.3.0-canary-b546603b-20260121 + react-dom: 19.3.0-canary-b546603b-20260121(react@19.3.0-canary-b546603b-20260121) optionalDependencies: '@types/react': 19.2.2 '@types/react-dom': 19.2.1(@types/react@19.2.2) - '@radix-ui/react-popper@1.2.1(@types/react-dom@19.2.1(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.3.0-canary-d2908752-20260119(react@19.3.0-canary-d2908752-20260119))(react@19.3.0-canary-d2908752-20260119)': - dependencies: - '@floating-ui/react-dom': 2.1.5(react-dom@19.3.0-canary-d2908752-20260119(react@19.3.0-canary-d2908752-20260119))(react@19.3.0-canary-d2908752-20260119) - '@radix-ui/react-arrow': 1.1.1(@types/react-dom@19.2.1(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.3.0-canary-d2908752-20260119(react@19.3.0-canary-d2908752-20260119))(react@19.3.0-canary-d2908752-20260119) - '@radix-ui/react-compose-refs': 1.1.1(@types/react@19.2.2)(react@19.3.0-canary-d2908752-20260119) - '@radix-ui/react-context': 1.1.1(@types/react@19.2.2)(react@19.3.0-canary-d2908752-20260119) - '@radix-ui/react-primitive': 2.0.1(@types/react-dom@19.2.1(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.3.0-canary-d2908752-20260119(react@19.3.0-canary-d2908752-20260119))(react@19.3.0-canary-d2908752-20260119) - '@radix-ui/react-use-callback-ref': 1.1.0(@types/react@19.2.2)(react@19.3.0-canary-d2908752-20260119) - '@radix-ui/react-use-layout-effect': 1.1.0(@types/react@19.2.2)(react@19.3.0-canary-d2908752-20260119) - '@radix-ui/react-use-rect': 1.1.0(@types/react@19.2.2)(react@19.3.0-canary-d2908752-20260119) - '@radix-ui/react-use-size': 1.1.0(@types/react@19.2.2)(react@19.3.0-canary-d2908752-20260119) + '@radix-ui/react-popper@1.2.1(@types/react-dom@19.2.1(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.3.0-canary-b546603b-20260121(react@19.3.0-canary-b546603b-20260121))(react@19.3.0-canary-b546603b-20260121)': + dependencies: + '@floating-ui/react-dom': 2.1.5(react-dom@19.3.0-canary-b546603b-20260121(react@19.3.0-canary-b546603b-20260121))(react@19.3.0-canary-b546603b-20260121) + '@radix-ui/react-arrow': 1.1.1(@types/react-dom@19.2.1(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.3.0-canary-b546603b-20260121(react@19.3.0-canary-b546603b-20260121))(react@19.3.0-canary-b546603b-20260121) + '@radix-ui/react-compose-refs': 1.1.1(@types/react@19.2.2)(react@19.3.0-canary-b546603b-20260121) + '@radix-ui/react-context': 1.1.1(@types/react@19.2.2)(react@19.3.0-canary-b546603b-20260121) + '@radix-ui/react-primitive': 2.0.1(@types/react-dom@19.2.1(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.3.0-canary-b546603b-20260121(react@19.3.0-canary-b546603b-20260121))(react@19.3.0-canary-b546603b-20260121) + '@radix-ui/react-use-callback-ref': 1.1.0(@types/react@19.2.2)(react@19.3.0-canary-b546603b-20260121) + '@radix-ui/react-use-layout-effect': 1.1.0(@types/react@19.2.2)(react@19.3.0-canary-b546603b-20260121) + '@radix-ui/react-use-rect': 1.1.0(@types/react@19.2.2)(react@19.3.0-canary-b546603b-20260121) + '@radix-ui/react-use-size': 1.1.0(@types/react@19.2.2)(react@19.3.0-canary-b546603b-20260121) '@radix-ui/rect': 1.1.0 - react: 19.3.0-canary-d2908752-20260119 - react-dom: 19.3.0-canary-d2908752-20260119(react@19.3.0-canary-d2908752-20260119) + react: 19.3.0-canary-b546603b-20260121 + react-dom: 19.3.0-canary-b546603b-20260121(react@19.3.0-canary-b546603b-20260121) optionalDependencies: '@types/react': 19.2.2 '@types/react-dom': 19.2.1(@types/react@19.2.2) - '@radix-ui/react-popper@1.2.8(@types/react-dom@19.2.1(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.3.0-canary-d2908752-20260119(react@19.3.0-canary-d2908752-20260119))(react@19.3.0-canary-d2908752-20260119)': - dependencies: - '@floating-ui/react-dom': 2.1.5(react-dom@19.3.0-canary-d2908752-20260119(react@19.3.0-canary-d2908752-20260119))(react@19.3.0-canary-d2908752-20260119) - '@radix-ui/react-arrow': 1.1.7(@types/react-dom@19.2.1(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.3.0-canary-d2908752-20260119(react@19.3.0-canary-d2908752-20260119))(react@19.3.0-canary-d2908752-20260119) - '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.2)(react@19.3.0-canary-d2908752-20260119) - '@radix-ui/react-context': 1.1.2(@types/react@19.2.2)(react@19.3.0-canary-d2908752-20260119) - '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.1(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.3.0-canary-d2908752-20260119(react@19.3.0-canary-d2908752-20260119))(react@19.3.0-canary-d2908752-20260119) - '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@19.2.2)(react@19.3.0-canary-d2908752-20260119) - '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.2.2)(react@19.3.0-canary-d2908752-20260119) - '@radix-ui/react-use-rect': 1.1.1(@types/react@19.2.2)(react@19.3.0-canary-d2908752-20260119) - '@radix-ui/react-use-size': 1.1.1(@types/react@19.2.2)(react@19.3.0-canary-d2908752-20260119) + '@radix-ui/react-popper@1.2.8(@types/react-dom@19.2.1(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.3.0-canary-b546603b-20260121(react@19.3.0-canary-b546603b-20260121))(react@19.3.0-canary-b546603b-20260121)': + dependencies: + '@floating-ui/react-dom': 2.1.5(react-dom@19.3.0-canary-b546603b-20260121(react@19.3.0-canary-b546603b-20260121))(react@19.3.0-canary-b546603b-20260121) + '@radix-ui/react-arrow': 1.1.7(@types/react-dom@19.2.1(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.3.0-canary-b546603b-20260121(react@19.3.0-canary-b546603b-20260121))(react@19.3.0-canary-b546603b-20260121) + '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.2)(react@19.3.0-canary-b546603b-20260121) + '@radix-ui/react-context': 1.1.2(@types/react@19.2.2)(react@19.3.0-canary-b546603b-20260121) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.1(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.3.0-canary-b546603b-20260121(react@19.3.0-canary-b546603b-20260121))(react@19.3.0-canary-b546603b-20260121) + '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@19.2.2)(react@19.3.0-canary-b546603b-20260121) + '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.2.2)(react@19.3.0-canary-b546603b-20260121) + '@radix-ui/react-use-rect': 1.1.1(@types/react@19.2.2)(react@19.3.0-canary-b546603b-20260121) + '@radix-ui/react-use-size': 1.1.1(@types/react@19.2.2)(react@19.3.0-canary-b546603b-20260121) '@radix-ui/rect': 1.1.1 - react: 19.3.0-canary-d2908752-20260119 - react-dom: 19.3.0-canary-d2908752-20260119(react@19.3.0-canary-d2908752-20260119) + react: 19.3.0-canary-b546603b-20260121 + react-dom: 19.3.0-canary-b546603b-20260121(react@19.3.0-canary-b546603b-20260121) optionalDependencies: '@types/react': 19.2.2 '@types/react-dom': 19.2.1(@types/react@19.2.2) - '@radix-ui/react-portal@1.1.2(@types/react-dom@19.2.1(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.3.0-canary-d2908752-20260119(react@19.3.0-canary-d2908752-20260119))(react@19.3.0-canary-d2908752-20260119)': + '@radix-ui/react-portal@1.1.2(@types/react-dom@19.2.1(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.3.0-canary-b546603b-20260121(react@19.3.0-canary-b546603b-20260121))(react@19.3.0-canary-b546603b-20260121)': dependencies: - '@radix-ui/react-primitive': 2.0.0(@types/react-dom@19.2.1(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.3.0-canary-d2908752-20260119(react@19.3.0-canary-d2908752-20260119))(react@19.3.0-canary-d2908752-20260119) - '@radix-ui/react-use-layout-effect': 1.1.0(@types/react@19.2.2)(react@19.3.0-canary-d2908752-20260119) - react: 19.3.0-canary-d2908752-20260119 - react-dom: 19.3.0-canary-d2908752-20260119(react@19.3.0-canary-d2908752-20260119) + '@radix-ui/react-primitive': 2.0.0(@types/react-dom@19.2.1(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.3.0-canary-b546603b-20260121(react@19.3.0-canary-b546603b-20260121))(react@19.3.0-canary-b546603b-20260121) + '@radix-ui/react-use-layout-effect': 1.1.0(@types/react@19.2.2)(react@19.3.0-canary-b546603b-20260121) + react: 19.3.0-canary-b546603b-20260121 + react-dom: 19.3.0-canary-b546603b-20260121(react@19.3.0-canary-b546603b-20260121) optionalDependencies: '@types/react': 19.2.2 '@types/react-dom': 19.2.1(@types/react@19.2.2) - '@radix-ui/react-portal@1.1.3(@types/react-dom@19.2.1(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.3.0-canary-d2908752-20260119(react@19.3.0-canary-d2908752-20260119))(react@19.3.0-canary-d2908752-20260119)': + '@radix-ui/react-portal@1.1.3(@types/react-dom@19.2.1(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.3.0-canary-b546603b-20260121(react@19.3.0-canary-b546603b-20260121))(react@19.3.0-canary-b546603b-20260121)': dependencies: - '@radix-ui/react-primitive': 2.0.1(@types/react-dom@19.2.1(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.3.0-canary-d2908752-20260119(react@19.3.0-canary-d2908752-20260119))(react@19.3.0-canary-d2908752-20260119) - '@radix-ui/react-use-layout-effect': 1.1.0(@types/react@19.2.2)(react@19.3.0-canary-d2908752-20260119) - react: 19.3.0-canary-d2908752-20260119 - react-dom: 19.3.0-canary-d2908752-20260119(react@19.3.0-canary-d2908752-20260119) + '@radix-ui/react-primitive': 2.0.1(@types/react-dom@19.2.1(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.3.0-canary-b546603b-20260121(react@19.3.0-canary-b546603b-20260121))(react@19.3.0-canary-b546603b-20260121) + '@radix-ui/react-use-layout-effect': 1.1.0(@types/react@19.2.2)(react@19.3.0-canary-b546603b-20260121) + react: 19.3.0-canary-b546603b-20260121 + react-dom: 19.3.0-canary-b546603b-20260121(react@19.3.0-canary-b546603b-20260121) optionalDependencies: '@types/react': 19.2.2 '@types/react-dom': 19.2.1(@types/react@19.2.2) - '@radix-ui/react-portal@1.1.9(@types/react-dom@19.2.1(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.3.0-canary-d2908752-20260119(react@19.3.0-canary-d2908752-20260119))(react@19.3.0-canary-d2908752-20260119)': + '@radix-ui/react-portal@1.1.9(@types/react-dom@19.2.1(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.3.0-canary-b546603b-20260121(react@19.3.0-canary-b546603b-20260121))(react@19.3.0-canary-b546603b-20260121)': dependencies: - '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.1(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.3.0-canary-d2908752-20260119(react@19.3.0-canary-d2908752-20260119))(react@19.3.0-canary-d2908752-20260119) - '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.2.2)(react@19.3.0-canary-d2908752-20260119) - react: 19.3.0-canary-d2908752-20260119 - react-dom: 19.3.0-canary-d2908752-20260119(react@19.3.0-canary-d2908752-20260119) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.1(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.3.0-canary-b546603b-20260121(react@19.3.0-canary-b546603b-20260121))(react@19.3.0-canary-b546603b-20260121) + '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.2.2)(react@19.3.0-canary-b546603b-20260121) + react: 19.3.0-canary-b546603b-20260121 + react-dom: 19.3.0-canary-b546603b-20260121(react@19.3.0-canary-b546603b-20260121) optionalDependencies: '@types/react': 19.2.2 '@types/react-dom': 19.2.1(@types/react@19.2.2) - '@radix-ui/react-presence@1.1.1(@types/react-dom@19.2.1(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.3.0-canary-d2908752-20260119(react@19.3.0-canary-d2908752-20260119))(react@19.3.0-canary-d2908752-20260119)': + '@radix-ui/react-presence@1.1.1(@types/react-dom@19.2.1(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.3.0-canary-b546603b-20260121(react@19.3.0-canary-b546603b-20260121))(react@19.3.0-canary-b546603b-20260121)': dependencies: - '@radix-ui/react-compose-refs': 1.1.0(@types/react@19.2.2)(react@19.3.0-canary-d2908752-20260119) - '@radix-ui/react-use-layout-effect': 1.1.0(@types/react@19.2.2)(react@19.3.0-canary-d2908752-20260119) - react: 19.3.0-canary-d2908752-20260119 - react-dom: 19.3.0-canary-d2908752-20260119(react@19.3.0-canary-d2908752-20260119) + '@radix-ui/react-compose-refs': 1.1.0(@types/react@19.2.2)(react@19.3.0-canary-b546603b-20260121) + '@radix-ui/react-use-layout-effect': 1.1.0(@types/react@19.2.2)(react@19.3.0-canary-b546603b-20260121) + react: 19.3.0-canary-b546603b-20260121 + react-dom: 19.3.0-canary-b546603b-20260121(react@19.3.0-canary-b546603b-20260121) optionalDependencies: '@types/react': 19.2.2 '@types/react-dom': 19.2.1(@types/react@19.2.2) - '@radix-ui/react-presence@1.1.2(@types/react-dom@19.2.1(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.3.0-canary-d2908752-20260119(react@19.3.0-canary-d2908752-20260119))(react@19.3.0-canary-d2908752-20260119)': + '@radix-ui/react-presence@1.1.2(@types/react-dom@19.2.1(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.3.0-canary-b546603b-20260121(react@19.3.0-canary-b546603b-20260121))(react@19.3.0-canary-b546603b-20260121)': dependencies: - '@radix-ui/react-compose-refs': 1.1.1(@types/react@19.2.2)(react@19.3.0-canary-d2908752-20260119) - '@radix-ui/react-use-layout-effect': 1.1.0(@types/react@19.2.2)(react@19.3.0-canary-d2908752-20260119) - react: 19.3.0-canary-d2908752-20260119 - react-dom: 19.3.0-canary-d2908752-20260119(react@19.3.0-canary-d2908752-20260119) + '@radix-ui/react-compose-refs': 1.1.1(@types/react@19.2.2)(react@19.3.0-canary-b546603b-20260121) + '@radix-ui/react-use-layout-effect': 1.1.0(@types/react@19.2.2)(react@19.3.0-canary-b546603b-20260121) + react: 19.3.0-canary-b546603b-20260121 + react-dom: 19.3.0-canary-b546603b-20260121(react@19.3.0-canary-b546603b-20260121) optionalDependencies: '@types/react': 19.2.2 '@types/react-dom': 19.2.1(@types/react@19.2.2) - '@radix-ui/react-presence@1.1.5(@types/react-dom@19.2.1(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.3.0-canary-d2908752-20260119(react@19.3.0-canary-d2908752-20260119))(react@19.3.0-canary-d2908752-20260119)': + '@radix-ui/react-presence@1.1.5(@types/react-dom@19.2.1(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.3.0-canary-b546603b-20260121(react@19.3.0-canary-b546603b-20260121))(react@19.3.0-canary-b546603b-20260121)': dependencies: - '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.2)(react@19.3.0-canary-d2908752-20260119) - '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.2.2)(react@19.3.0-canary-d2908752-20260119) - react: 19.3.0-canary-d2908752-20260119 - react-dom: 19.3.0-canary-d2908752-20260119(react@19.3.0-canary-d2908752-20260119) + '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.2)(react@19.3.0-canary-b546603b-20260121) + '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.2.2)(react@19.3.0-canary-b546603b-20260121) + react: 19.3.0-canary-b546603b-20260121 + react-dom: 19.3.0-canary-b546603b-20260121(react@19.3.0-canary-b546603b-20260121) optionalDependencies: '@types/react': 19.2.2 '@types/react-dom': 19.2.1(@types/react@19.2.2) - '@radix-ui/react-primitive@2.0.0(@types/react-dom@19.2.1(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.3.0-canary-d2908752-20260119(react@19.3.0-canary-d2908752-20260119))(react@19.3.0-canary-d2908752-20260119)': + '@radix-ui/react-primitive@2.0.0(@types/react-dom@19.2.1(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.3.0-canary-b546603b-20260121(react@19.3.0-canary-b546603b-20260121))(react@19.3.0-canary-b546603b-20260121)': dependencies: - '@radix-ui/react-slot': 1.1.0(@types/react@19.2.2)(react@19.3.0-canary-d2908752-20260119) - react: 19.3.0-canary-d2908752-20260119 - react-dom: 19.3.0-canary-d2908752-20260119(react@19.3.0-canary-d2908752-20260119) + '@radix-ui/react-slot': 1.1.0(@types/react@19.2.2)(react@19.3.0-canary-b546603b-20260121) + react: 19.3.0-canary-b546603b-20260121 + react-dom: 19.3.0-canary-b546603b-20260121(react@19.3.0-canary-b546603b-20260121) optionalDependencies: '@types/react': 19.2.2 '@types/react-dom': 19.2.1(@types/react@19.2.2) - '@radix-ui/react-primitive@2.0.1(@types/react-dom@19.2.1(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.3.0-canary-d2908752-20260119(react@19.3.0-canary-d2908752-20260119))(react@19.3.0-canary-d2908752-20260119)': + '@radix-ui/react-primitive@2.0.1(@types/react-dom@19.2.1(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.3.0-canary-b546603b-20260121(react@19.3.0-canary-b546603b-20260121))(react@19.3.0-canary-b546603b-20260121)': dependencies: - '@radix-ui/react-slot': 1.1.1(@types/react@19.2.2)(react@19.3.0-canary-d2908752-20260119) - react: 19.3.0-canary-d2908752-20260119 - react-dom: 19.3.0-canary-d2908752-20260119(react@19.3.0-canary-d2908752-20260119) + '@radix-ui/react-slot': 1.1.1(@types/react@19.2.2)(react@19.3.0-canary-b546603b-20260121) + react: 19.3.0-canary-b546603b-20260121 + react-dom: 19.3.0-canary-b546603b-20260121(react@19.3.0-canary-b546603b-20260121) optionalDependencies: '@types/react': 19.2.2 '@types/react-dom': 19.2.1(@types/react@19.2.2) - '@radix-ui/react-primitive@2.1.3(@types/react-dom@19.2.1(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.3.0-canary-d2908752-20260119(react@19.3.0-canary-d2908752-20260119))(react@19.3.0-canary-d2908752-20260119)': + '@radix-ui/react-primitive@2.1.3(@types/react-dom@19.2.1(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.3.0-canary-b546603b-20260121(react@19.3.0-canary-b546603b-20260121))(react@19.3.0-canary-b546603b-20260121)': dependencies: - '@radix-ui/react-slot': 1.2.3(@types/react@19.2.2)(react@19.3.0-canary-d2908752-20260119) - react: 19.3.0-canary-d2908752-20260119 - react-dom: 19.3.0-canary-d2908752-20260119(react@19.3.0-canary-d2908752-20260119) + '@radix-ui/react-slot': 1.2.3(@types/react@19.2.2)(react@19.3.0-canary-b546603b-20260121) + react: 19.3.0-canary-b546603b-20260121 + react-dom: 19.3.0-canary-b546603b-20260121(react@19.3.0-canary-b546603b-20260121) optionalDependencies: '@types/react': 19.2.2 '@types/react-dom': 19.2.1(@types/react@19.2.2) - '@radix-ui/react-roving-focus@1.1.1(@types/react-dom@19.2.1(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.3.0-canary-d2908752-20260119(react@19.3.0-canary-d2908752-20260119))(react@19.3.0-canary-d2908752-20260119)': + '@radix-ui/react-roving-focus@1.1.1(@types/react-dom@19.2.1(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.3.0-canary-b546603b-20260121(react@19.3.0-canary-b546603b-20260121))(react@19.3.0-canary-b546603b-20260121)': dependencies: '@radix-ui/primitive': 1.1.1 - '@radix-ui/react-collection': 1.1.1(@types/react-dom@19.2.1(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.3.0-canary-d2908752-20260119(react@19.3.0-canary-d2908752-20260119))(react@19.3.0-canary-d2908752-20260119) - '@radix-ui/react-compose-refs': 1.1.1(@types/react@19.2.2)(react@19.3.0-canary-d2908752-20260119) - '@radix-ui/react-context': 1.1.1(@types/react@19.2.2)(react@19.3.0-canary-d2908752-20260119) - '@radix-ui/react-direction': 1.1.0(@types/react@19.2.2)(react@19.3.0-canary-d2908752-20260119) - '@radix-ui/react-id': 1.1.0(@types/react@19.2.2)(react@19.3.0-canary-d2908752-20260119) - '@radix-ui/react-primitive': 2.0.1(@types/react-dom@19.2.1(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.3.0-canary-d2908752-20260119(react@19.3.0-canary-d2908752-20260119))(react@19.3.0-canary-d2908752-20260119) - '@radix-ui/react-use-callback-ref': 1.1.0(@types/react@19.2.2)(react@19.3.0-canary-d2908752-20260119) - '@radix-ui/react-use-controllable-state': 1.1.0(@types/react@19.2.2)(react@19.3.0-canary-d2908752-20260119) - react: 19.3.0-canary-d2908752-20260119 - react-dom: 19.3.0-canary-d2908752-20260119(react@19.3.0-canary-d2908752-20260119) + '@radix-ui/react-collection': 1.1.1(@types/react-dom@19.2.1(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.3.0-canary-b546603b-20260121(react@19.3.0-canary-b546603b-20260121))(react@19.3.0-canary-b546603b-20260121) + '@radix-ui/react-compose-refs': 1.1.1(@types/react@19.2.2)(react@19.3.0-canary-b546603b-20260121) + '@radix-ui/react-context': 1.1.1(@types/react@19.2.2)(react@19.3.0-canary-b546603b-20260121) + '@radix-ui/react-direction': 1.1.0(@types/react@19.2.2)(react@19.3.0-canary-b546603b-20260121) + '@radix-ui/react-id': 1.1.0(@types/react@19.2.2)(react@19.3.0-canary-b546603b-20260121) + '@radix-ui/react-primitive': 2.0.1(@types/react-dom@19.2.1(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.3.0-canary-b546603b-20260121(react@19.3.0-canary-b546603b-20260121))(react@19.3.0-canary-b546603b-20260121) + '@radix-ui/react-use-callback-ref': 1.1.0(@types/react@19.2.2)(react@19.3.0-canary-b546603b-20260121) + '@radix-ui/react-use-controllable-state': 1.1.0(@types/react@19.2.2)(react@19.3.0-canary-b546603b-20260121) + react: 19.3.0-canary-b546603b-20260121 + react-dom: 19.3.0-canary-b546603b-20260121(react@19.3.0-canary-b546603b-20260121) optionalDependencies: '@types/react': 19.2.2 '@types/react-dom': 19.2.1(@types/react@19.2.2) - '@radix-ui/react-roving-focus@1.1.11(@types/react-dom@19.2.1(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.3.0-canary-d2908752-20260119(react@19.3.0-canary-d2908752-20260119))(react@19.3.0-canary-d2908752-20260119)': + '@radix-ui/react-roving-focus@1.1.11(@types/react-dom@19.2.1(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.3.0-canary-b546603b-20260121(react@19.3.0-canary-b546603b-20260121))(react@19.3.0-canary-b546603b-20260121)': dependencies: '@radix-ui/primitive': 1.1.3 - '@radix-ui/react-collection': 1.1.7(@types/react-dom@19.2.1(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.3.0-canary-d2908752-20260119(react@19.3.0-canary-d2908752-20260119))(react@19.3.0-canary-d2908752-20260119) - '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.2)(react@19.3.0-canary-d2908752-20260119) - '@radix-ui/react-context': 1.1.2(@types/react@19.2.2)(react@19.3.0-canary-d2908752-20260119) - '@radix-ui/react-direction': 1.1.1(@types/react@19.2.2)(react@19.3.0-canary-d2908752-20260119) - '@radix-ui/react-id': 1.1.1(@types/react@19.2.2)(react@19.3.0-canary-d2908752-20260119) - '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.1(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.3.0-canary-d2908752-20260119(react@19.3.0-canary-d2908752-20260119))(react@19.3.0-canary-d2908752-20260119) - '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@19.2.2)(react@19.3.0-canary-d2908752-20260119) - '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@19.2.2)(react@19.3.0-canary-d2908752-20260119) - react: 19.3.0-canary-d2908752-20260119 - react-dom: 19.3.0-canary-d2908752-20260119(react@19.3.0-canary-d2908752-20260119) + '@radix-ui/react-collection': 1.1.7(@types/react-dom@19.2.1(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.3.0-canary-b546603b-20260121(react@19.3.0-canary-b546603b-20260121))(react@19.3.0-canary-b546603b-20260121) + '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.2)(react@19.3.0-canary-b546603b-20260121) + '@radix-ui/react-context': 1.1.2(@types/react@19.2.2)(react@19.3.0-canary-b546603b-20260121) + '@radix-ui/react-direction': 1.1.1(@types/react@19.2.2)(react@19.3.0-canary-b546603b-20260121) + '@radix-ui/react-id': 1.1.1(@types/react@19.2.2)(react@19.3.0-canary-b546603b-20260121) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.1(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.3.0-canary-b546603b-20260121(react@19.3.0-canary-b546603b-20260121))(react@19.3.0-canary-b546603b-20260121) + '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@19.2.2)(react@19.3.0-canary-b546603b-20260121) + '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@19.2.2)(react@19.3.0-canary-b546603b-20260121) + react: 19.3.0-canary-b546603b-20260121 + react-dom: 19.3.0-canary-b546603b-20260121(react@19.3.0-canary-b546603b-20260121) optionalDependencies: '@types/react': 19.2.2 '@types/react-dom': 19.2.1(@types/react@19.2.2) - '@radix-ui/react-scroll-area@1.2.10(@types/react-dom@19.2.1(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.3.0-canary-d2908752-20260119(react@19.3.0-canary-d2908752-20260119))(react@19.3.0-canary-d2908752-20260119)': + '@radix-ui/react-scroll-area@1.2.10(@types/react-dom@19.2.1(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.3.0-canary-b546603b-20260121(react@19.3.0-canary-b546603b-20260121))(react@19.3.0-canary-b546603b-20260121)': dependencies: '@radix-ui/number': 1.1.1 '@radix-ui/primitive': 1.1.3 - '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.2)(react@19.3.0-canary-d2908752-20260119) - '@radix-ui/react-context': 1.1.2(@types/react@19.2.2)(react@19.3.0-canary-d2908752-20260119) - '@radix-ui/react-direction': 1.1.1(@types/react@19.2.2)(react@19.3.0-canary-d2908752-20260119) - '@radix-ui/react-presence': 1.1.5(@types/react-dom@19.2.1(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.3.0-canary-d2908752-20260119(react@19.3.0-canary-d2908752-20260119))(react@19.3.0-canary-d2908752-20260119) - '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.1(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.3.0-canary-d2908752-20260119(react@19.3.0-canary-d2908752-20260119))(react@19.3.0-canary-d2908752-20260119) - '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@19.2.2)(react@19.3.0-canary-d2908752-20260119) - '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.2.2)(react@19.3.0-canary-d2908752-20260119) - react: 19.3.0-canary-d2908752-20260119 - react-dom: 19.3.0-canary-d2908752-20260119(react@19.3.0-canary-d2908752-20260119) + '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.2)(react@19.3.0-canary-b546603b-20260121) + '@radix-ui/react-context': 1.1.2(@types/react@19.2.2)(react@19.3.0-canary-b546603b-20260121) + '@radix-ui/react-direction': 1.1.1(@types/react@19.2.2)(react@19.3.0-canary-b546603b-20260121) + '@radix-ui/react-presence': 1.1.5(@types/react-dom@19.2.1(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.3.0-canary-b546603b-20260121(react@19.3.0-canary-b546603b-20260121))(react@19.3.0-canary-b546603b-20260121) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.1(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.3.0-canary-b546603b-20260121(react@19.3.0-canary-b546603b-20260121))(react@19.3.0-canary-b546603b-20260121) + '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@19.2.2)(react@19.3.0-canary-b546603b-20260121) + '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.2.2)(react@19.3.0-canary-b546603b-20260121) + react: 19.3.0-canary-b546603b-20260121 + react-dom: 19.3.0-canary-b546603b-20260121(react@19.3.0-canary-b546603b-20260121) optionalDependencies: '@types/react': 19.2.2 '@types/react-dom': 19.2.1(@types/react@19.2.2) - '@radix-ui/react-select@2.2.6(@types/react-dom@19.2.1(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.3.0-canary-d2908752-20260119(react@19.3.0-canary-d2908752-20260119))(react@19.3.0-canary-d2908752-20260119)': + '@radix-ui/react-select@2.2.6(@types/react-dom@19.2.1(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.3.0-canary-b546603b-20260121(react@19.3.0-canary-b546603b-20260121))(react@19.3.0-canary-b546603b-20260121)': dependencies: '@radix-ui/number': 1.1.1 '@radix-ui/primitive': 1.1.3 - '@radix-ui/react-collection': 1.1.7(@types/react-dom@19.2.1(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.3.0-canary-d2908752-20260119(react@19.3.0-canary-d2908752-20260119))(react@19.3.0-canary-d2908752-20260119) - '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.2)(react@19.3.0-canary-d2908752-20260119) - '@radix-ui/react-context': 1.1.2(@types/react@19.2.2)(react@19.3.0-canary-d2908752-20260119) - '@radix-ui/react-direction': 1.1.1(@types/react@19.2.2)(react@19.3.0-canary-d2908752-20260119) - '@radix-ui/react-dismissable-layer': 1.1.11(@types/react-dom@19.2.1(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.3.0-canary-d2908752-20260119(react@19.3.0-canary-d2908752-20260119))(react@19.3.0-canary-d2908752-20260119) - '@radix-ui/react-focus-guards': 1.1.3(@types/react@19.2.2)(react@19.3.0-canary-d2908752-20260119) - '@radix-ui/react-focus-scope': 1.1.7(@types/react-dom@19.2.1(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.3.0-canary-d2908752-20260119(react@19.3.0-canary-d2908752-20260119))(react@19.3.0-canary-d2908752-20260119) - '@radix-ui/react-id': 1.1.1(@types/react@19.2.2)(react@19.3.0-canary-d2908752-20260119) - '@radix-ui/react-popper': 1.2.8(@types/react-dom@19.2.1(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.3.0-canary-d2908752-20260119(react@19.3.0-canary-d2908752-20260119))(react@19.3.0-canary-d2908752-20260119) - '@radix-ui/react-portal': 1.1.9(@types/react-dom@19.2.1(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.3.0-canary-d2908752-20260119(react@19.3.0-canary-d2908752-20260119))(react@19.3.0-canary-d2908752-20260119) - '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.1(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.3.0-canary-d2908752-20260119(react@19.3.0-canary-d2908752-20260119))(react@19.3.0-canary-d2908752-20260119) - '@radix-ui/react-slot': 1.2.3(@types/react@19.2.2)(react@19.3.0-canary-d2908752-20260119) - '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@19.2.2)(react@19.3.0-canary-d2908752-20260119) - '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@19.2.2)(react@19.3.0-canary-d2908752-20260119) - '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.2.2)(react@19.3.0-canary-d2908752-20260119) - '@radix-ui/react-use-previous': 1.1.1(@types/react@19.2.2)(react@19.3.0-canary-d2908752-20260119) - '@radix-ui/react-visually-hidden': 1.2.3(@types/react-dom@19.2.1(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.3.0-canary-d2908752-20260119(react@19.3.0-canary-d2908752-20260119))(react@19.3.0-canary-d2908752-20260119) + '@radix-ui/react-collection': 1.1.7(@types/react-dom@19.2.1(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.3.0-canary-b546603b-20260121(react@19.3.0-canary-b546603b-20260121))(react@19.3.0-canary-b546603b-20260121) + '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.2)(react@19.3.0-canary-b546603b-20260121) + '@radix-ui/react-context': 1.1.2(@types/react@19.2.2)(react@19.3.0-canary-b546603b-20260121) + '@radix-ui/react-direction': 1.1.1(@types/react@19.2.2)(react@19.3.0-canary-b546603b-20260121) + '@radix-ui/react-dismissable-layer': 1.1.11(@types/react-dom@19.2.1(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.3.0-canary-b546603b-20260121(react@19.3.0-canary-b546603b-20260121))(react@19.3.0-canary-b546603b-20260121) + '@radix-ui/react-focus-guards': 1.1.3(@types/react@19.2.2)(react@19.3.0-canary-b546603b-20260121) + '@radix-ui/react-focus-scope': 1.1.7(@types/react-dom@19.2.1(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.3.0-canary-b546603b-20260121(react@19.3.0-canary-b546603b-20260121))(react@19.3.0-canary-b546603b-20260121) + '@radix-ui/react-id': 1.1.1(@types/react@19.2.2)(react@19.3.0-canary-b546603b-20260121) + '@radix-ui/react-popper': 1.2.8(@types/react-dom@19.2.1(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.3.0-canary-b546603b-20260121(react@19.3.0-canary-b546603b-20260121))(react@19.3.0-canary-b546603b-20260121) + '@radix-ui/react-portal': 1.1.9(@types/react-dom@19.2.1(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.3.0-canary-b546603b-20260121(react@19.3.0-canary-b546603b-20260121))(react@19.3.0-canary-b546603b-20260121) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.1(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.3.0-canary-b546603b-20260121(react@19.3.0-canary-b546603b-20260121))(react@19.3.0-canary-b546603b-20260121) + '@radix-ui/react-slot': 1.2.3(@types/react@19.2.2)(react@19.3.0-canary-b546603b-20260121) + '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@19.2.2)(react@19.3.0-canary-b546603b-20260121) + '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@19.2.2)(react@19.3.0-canary-b546603b-20260121) + '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.2.2)(react@19.3.0-canary-b546603b-20260121) + '@radix-ui/react-use-previous': 1.1.1(@types/react@19.2.2)(react@19.3.0-canary-b546603b-20260121) + '@radix-ui/react-visually-hidden': 1.2.3(@types/react-dom@19.2.1(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.3.0-canary-b546603b-20260121(react@19.3.0-canary-b546603b-20260121))(react@19.3.0-canary-b546603b-20260121) aria-hidden: 1.2.6 - react: 19.3.0-canary-d2908752-20260119 - react-dom: 19.3.0-canary-d2908752-20260119(react@19.3.0-canary-d2908752-20260119) - react-remove-scroll: 2.7.1(@types/react@19.2.2)(react@19.3.0-canary-d2908752-20260119) + react: 19.3.0-canary-b546603b-20260121 + react-dom: 19.3.0-canary-b546603b-20260121(react@19.3.0-canary-b546603b-20260121) + react-remove-scroll: 2.7.1(@types/react@19.2.2)(react@19.3.0-canary-b546603b-20260121) optionalDependencies: '@types/react': 19.2.2 '@types/react-dom': 19.2.1(@types/react@19.2.2) - '@radix-ui/react-slot@1.1.0(@types/react@19.2.2)(react@19.3.0-canary-d2908752-20260119)': + '@radix-ui/react-slot@1.1.0(@types/react@19.2.2)(react@19.3.0-canary-b546603b-20260121)': dependencies: - '@radix-ui/react-compose-refs': 1.1.0(@types/react@19.2.2)(react@19.3.0-canary-d2908752-20260119) - react: 19.3.0-canary-d2908752-20260119 + '@radix-ui/react-compose-refs': 1.1.0(@types/react@19.2.2)(react@19.3.0-canary-b546603b-20260121) + react: 19.3.0-canary-b546603b-20260121 optionalDependencies: '@types/react': 19.2.2 - '@radix-ui/react-slot@1.1.1(@types/react@19.2.2)(react@19.3.0-canary-d2908752-20260119)': + '@radix-ui/react-slot@1.1.1(@types/react@19.2.2)(react@19.3.0-canary-b546603b-20260121)': dependencies: - '@radix-ui/react-compose-refs': 1.1.1(@types/react@19.2.2)(react@19.3.0-canary-d2908752-20260119) - react: 19.3.0-canary-d2908752-20260119 + '@radix-ui/react-compose-refs': 1.1.1(@types/react@19.2.2)(react@19.3.0-canary-b546603b-20260121) + react: 19.3.0-canary-b546603b-20260121 optionalDependencies: '@types/react': 19.2.2 - '@radix-ui/react-slot@1.2.3(@types/react@19.2.2)(react@19.3.0-canary-d2908752-20260119)': + '@radix-ui/react-slot@1.2.3(@types/react@19.2.2)(react@19.3.0-canary-b546603b-20260121)': dependencies: - '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.2)(react@19.3.0-canary-d2908752-20260119) - react: 19.3.0-canary-d2908752-20260119 + '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.2)(react@19.3.0-canary-b546603b-20260121) + react: 19.3.0-canary-b546603b-20260121 optionalDependencies: '@types/react': 19.2.2 - '@radix-ui/react-tabs@1.1.13(@types/react-dom@19.2.1(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.3.0-canary-d2908752-20260119(react@19.3.0-canary-d2908752-20260119))(react@19.3.0-canary-d2908752-20260119)': + '@radix-ui/react-tabs@1.1.13(@types/react-dom@19.2.1(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.3.0-canary-b546603b-20260121(react@19.3.0-canary-b546603b-20260121))(react@19.3.0-canary-b546603b-20260121)': dependencies: '@radix-ui/primitive': 1.1.3 - '@radix-ui/react-context': 1.1.2(@types/react@19.2.2)(react@19.3.0-canary-d2908752-20260119) - '@radix-ui/react-direction': 1.1.1(@types/react@19.2.2)(react@19.3.0-canary-d2908752-20260119) - '@radix-ui/react-id': 1.1.1(@types/react@19.2.2)(react@19.3.0-canary-d2908752-20260119) - '@radix-ui/react-presence': 1.1.5(@types/react-dom@19.2.1(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.3.0-canary-d2908752-20260119(react@19.3.0-canary-d2908752-20260119))(react@19.3.0-canary-d2908752-20260119) - '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.1(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.3.0-canary-d2908752-20260119(react@19.3.0-canary-d2908752-20260119))(react@19.3.0-canary-d2908752-20260119) - '@radix-ui/react-roving-focus': 1.1.11(@types/react-dom@19.2.1(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.3.0-canary-d2908752-20260119(react@19.3.0-canary-d2908752-20260119))(react@19.3.0-canary-d2908752-20260119) - '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@19.2.2)(react@19.3.0-canary-d2908752-20260119) - react: 19.3.0-canary-d2908752-20260119 - react-dom: 19.3.0-canary-d2908752-20260119(react@19.3.0-canary-d2908752-20260119) + '@radix-ui/react-context': 1.1.2(@types/react@19.2.2)(react@19.3.0-canary-b546603b-20260121) + '@radix-ui/react-direction': 1.1.1(@types/react@19.2.2)(react@19.3.0-canary-b546603b-20260121) + '@radix-ui/react-id': 1.1.1(@types/react@19.2.2)(react@19.3.0-canary-b546603b-20260121) + '@radix-ui/react-presence': 1.1.5(@types/react-dom@19.2.1(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.3.0-canary-b546603b-20260121(react@19.3.0-canary-b546603b-20260121))(react@19.3.0-canary-b546603b-20260121) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.1(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.3.0-canary-b546603b-20260121(react@19.3.0-canary-b546603b-20260121))(react@19.3.0-canary-b546603b-20260121) + '@radix-ui/react-roving-focus': 1.1.11(@types/react-dom@19.2.1(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.3.0-canary-b546603b-20260121(react@19.3.0-canary-b546603b-20260121))(react@19.3.0-canary-b546603b-20260121) + '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@19.2.2)(react@19.3.0-canary-b546603b-20260121) + react: 19.3.0-canary-b546603b-20260121 + react-dom: 19.3.0-canary-b546603b-20260121(react@19.3.0-canary-b546603b-20260121) optionalDependencies: '@types/react': 19.2.2 '@types/react-dom': 19.2.1(@types/react@19.2.2) - '@radix-ui/react-toggle-group@1.1.1(@types/react-dom@19.2.1(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.3.0-canary-d2908752-20260119(react@19.3.0-canary-d2908752-20260119))(react@19.3.0-canary-d2908752-20260119)': + '@radix-ui/react-toggle-group@1.1.1(@types/react-dom@19.2.1(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.3.0-canary-b546603b-20260121(react@19.3.0-canary-b546603b-20260121))(react@19.3.0-canary-b546603b-20260121)': dependencies: '@radix-ui/primitive': 1.1.1 - '@radix-ui/react-context': 1.1.1(@types/react@19.2.2)(react@19.3.0-canary-d2908752-20260119) - '@radix-ui/react-direction': 1.1.0(@types/react@19.2.2)(react@19.3.0-canary-d2908752-20260119) - '@radix-ui/react-primitive': 2.0.1(@types/react-dom@19.2.1(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.3.0-canary-d2908752-20260119(react@19.3.0-canary-d2908752-20260119))(react@19.3.0-canary-d2908752-20260119) - '@radix-ui/react-roving-focus': 1.1.1(@types/react-dom@19.2.1(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.3.0-canary-d2908752-20260119(react@19.3.0-canary-d2908752-20260119))(react@19.3.0-canary-d2908752-20260119) - '@radix-ui/react-toggle': 1.1.1(@types/react-dom@19.2.1(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.3.0-canary-d2908752-20260119(react@19.3.0-canary-d2908752-20260119))(react@19.3.0-canary-d2908752-20260119) - '@radix-ui/react-use-controllable-state': 1.1.0(@types/react@19.2.2)(react@19.3.0-canary-d2908752-20260119) - react: 19.3.0-canary-d2908752-20260119 - react-dom: 19.3.0-canary-d2908752-20260119(react@19.3.0-canary-d2908752-20260119) + '@radix-ui/react-context': 1.1.1(@types/react@19.2.2)(react@19.3.0-canary-b546603b-20260121) + '@radix-ui/react-direction': 1.1.0(@types/react@19.2.2)(react@19.3.0-canary-b546603b-20260121) + '@radix-ui/react-primitive': 2.0.1(@types/react-dom@19.2.1(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.3.0-canary-b546603b-20260121(react@19.3.0-canary-b546603b-20260121))(react@19.3.0-canary-b546603b-20260121) + '@radix-ui/react-roving-focus': 1.1.1(@types/react-dom@19.2.1(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.3.0-canary-b546603b-20260121(react@19.3.0-canary-b546603b-20260121))(react@19.3.0-canary-b546603b-20260121) + '@radix-ui/react-toggle': 1.1.1(@types/react-dom@19.2.1(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.3.0-canary-b546603b-20260121(react@19.3.0-canary-b546603b-20260121))(react@19.3.0-canary-b546603b-20260121) + '@radix-ui/react-use-controllable-state': 1.1.0(@types/react@19.2.2)(react@19.3.0-canary-b546603b-20260121) + react: 19.3.0-canary-b546603b-20260121 + react-dom: 19.3.0-canary-b546603b-20260121(react@19.3.0-canary-b546603b-20260121) optionalDependencies: '@types/react': 19.2.2 '@types/react-dom': 19.2.1(@types/react@19.2.2) - '@radix-ui/react-toggle@1.1.1(@types/react-dom@19.2.1(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.3.0-canary-d2908752-20260119(react@19.3.0-canary-d2908752-20260119))(react@19.3.0-canary-d2908752-20260119)': + '@radix-ui/react-toggle@1.1.1(@types/react-dom@19.2.1(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.3.0-canary-b546603b-20260121(react@19.3.0-canary-b546603b-20260121))(react@19.3.0-canary-b546603b-20260121)': dependencies: '@radix-ui/primitive': 1.1.1 - '@radix-ui/react-primitive': 2.0.1(@types/react-dom@19.2.1(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.3.0-canary-d2908752-20260119(react@19.3.0-canary-d2908752-20260119))(react@19.3.0-canary-d2908752-20260119) - '@radix-ui/react-use-controllable-state': 1.1.0(@types/react@19.2.2)(react@19.3.0-canary-d2908752-20260119) - react: 19.3.0-canary-d2908752-20260119 - react-dom: 19.3.0-canary-d2908752-20260119(react@19.3.0-canary-d2908752-20260119) + '@radix-ui/react-primitive': 2.0.1(@types/react-dom@19.2.1(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.3.0-canary-b546603b-20260121(react@19.3.0-canary-b546603b-20260121))(react@19.3.0-canary-b546603b-20260121) + '@radix-ui/react-use-controllable-state': 1.1.0(@types/react@19.2.2)(react@19.3.0-canary-b546603b-20260121) + react: 19.3.0-canary-b546603b-20260121 + react-dom: 19.3.0-canary-b546603b-20260121(react@19.3.0-canary-b546603b-20260121) optionalDependencies: '@types/react': 19.2.2 '@types/react-dom': 19.2.1(@types/react@19.2.2) - '@radix-ui/react-tooltip@1.1.4(@types/react-dom@19.2.1(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.3.0-canary-d2908752-20260119(react@19.3.0-canary-d2908752-20260119))(react@19.3.0-canary-d2908752-20260119)': + '@radix-ui/react-tooltip@1.1.4(@types/react-dom@19.2.1(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.3.0-canary-b546603b-20260121(react@19.3.0-canary-b546603b-20260121))(react@19.3.0-canary-b546603b-20260121)': dependencies: '@radix-ui/primitive': 1.1.0 - '@radix-ui/react-compose-refs': 1.1.0(@types/react@19.2.2)(react@19.3.0-canary-d2908752-20260119) - '@radix-ui/react-context': 1.1.1(@types/react@19.2.2)(react@19.3.0-canary-d2908752-20260119) - '@radix-ui/react-dismissable-layer': 1.1.1(@types/react-dom@19.2.1(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.3.0-canary-d2908752-20260119(react@19.3.0-canary-d2908752-20260119))(react@19.3.0-canary-d2908752-20260119) - '@radix-ui/react-id': 1.1.0(@types/react@19.2.2)(react@19.3.0-canary-d2908752-20260119) - '@radix-ui/react-popper': 1.2.0(@types/react-dom@19.2.1(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.3.0-canary-d2908752-20260119(react@19.3.0-canary-d2908752-20260119))(react@19.3.0-canary-d2908752-20260119) - '@radix-ui/react-portal': 1.1.2(@types/react-dom@19.2.1(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.3.0-canary-d2908752-20260119(react@19.3.0-canary-d2908752-20260119))(react@19.3.0-canary-d2908752-20260119) - '@radix-ui/react-presence': 1.1.1(@types/react-dom@19.2.1(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.3.0-canary-d2908752-20260119(react@19.3.0-canary-d2908752-20260119))(react@19.3.0-canary-d2908752-20260119) - '@radix-ui/react-primitive': 2.0.0(@types/react-dom@19.2.1(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.3.0-canary-d2908752-20260119(react@19.3.0-canary-d2908752-20260119))(react@19.3.0-canary-d2908752-20260119) - '@radix-ui/react-slot': 1.1.0(@types/react@19.2.2)(react@19.3.0-canary-d2908752-20260119) - '@radix-ui/react-use-controllable-state': 1.1.0(@types/react@19.2.2)(react@19.3.0-canary-d2908752-20260119) - '@radix-ui/react-visually-hidden': 1.1.0(@types/react-dom@19.2.1(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.3.0-canary-d2908752-20260119(react@19.3.0-canary-d2908752-20260119))(react@19.3.0-canary-d2908752-20260119) - react: 19.3.0-canary-d2908752-20260119 - react-dom: 19.3.0-canary-d2908752-20260119(react@19.3.0-canary-d2908752-20260119) + '@radix-ui/react-compose-refs': 1.1.0(@types/react@19.2.2)(react@19.3.0-canary-b546603b-20260121) + '@radix-ui/react-context': 1.1.1(@types/react@19.2.2)(react@19.3.0-canary-b546603b-20260121) + '@radix-ui/react-dismissable-layer': 1.1.1(@types/react-dom@19.2.1(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.3.0-canary-b546603b-20260121(react@19.3.0-canary-b546603b-20260121))(react@19.3.0-canary-b546603b-20260121) + '@radix-ui/react-id': 1.1.0(@types/react@19.2.2)(react@19.3.0-canary-b546603b-20260121) + '@radix-ui/react-popper': 1.2.0(@types/react-dom@19.2.1(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.3.0-canary-b546603b-20260121(react@19.3.0-canary-b546603b-20260121))(react@19.3.0-canary-b546603b-20260121) + '@radix-ui/react-portal': 1.1.2(@types/react-dom@19.2.1(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.3.0-canary-b546603b-20260121(react@19.3.0-canary-b546603b-20260121))(react@19.3.0-canary-b546603b-20260121) + '@radix-ui/react-presence': 1.1.1(@types/react-dom@19.2.1(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.3.0-canary-b546603b-20260121(react@19.3.0-canary-b546603b-20260121))(react@19.3.0-canary-b546603b-20260121) + '@radix-ui/react-primitive': 2.0.0(@types/react-dom@19.2.1(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.3.0-canary-b546603b-20260121(react@19.3.0-canary-b546603b-20260121))(react@19.3.0-canary-b546603b-20260121) + '@radix-ui/react-slot': 1.1.0(@types/react@19.2.2)(react@19.3.0-canary-b546603b-20260121) + '@radix-ui/react-use-controllable-state': 1.1.0(@types/react@19.2.2)(react@19.3.0-canary-b546603b-20260121) + '@radix-ui/react-visually-hidden': 1.1.0(@types/react-dom@19.2.1(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.3.0-canary-b546603b-20260121(react@19.3.0-canary-b546603b-20260121))(react@19.3.0-canary-b546603b-20260121) + react: 19.3.0-canary-b546603b-20260121 + react-dom: 19.3.0-canary-b546603b-20260121(react@19.3.0-canary-b546603b-20260121) optionalDependencies: '@types/react': 19.2.2 '@types/react-dom': 19.2.1(@types/react@19.2.2) - '@radix-ui/react-use-callback-ref@1.1.0(@types/react@19.2.2)(react@19.3.0-canary-d2908752-20260119)': + '@radix-ui/react-use-callback-ref@1.1.0(@types/react@19.2.2)(react@19.3.0-canary-b546603b-20260121)': dependencies: - react: 19.3.0-canary-d2908752-20260119 + react: 19.3.0-canary-b546603b-20260121 optionalDependencies: '@types/react': 19.2.2 - '@radix-ui/react-use-callback-ref@1.1.1(@types/react@19.2.2)(react@19.3.0-canary-d2908752-20260119)': + '@radix-ui/react-use-callback-ref@1.1.1(@types/react@19.2.2)(react@19.3.0-canary-b546603b-20260121)': dependencies: - react: 19.3.0-canary-d2908752-20260119 + react: 19.3.0-canary-b546603b-20260121 optionalDependencies: '@types/react': 19.2.2 - '@radix-ui/react-use-controllable-state@1.1.0(@types/react@19.2.2)(react@19.3.0-canary-d2908752-20260119)': + '@radix-ui/react-use-controllable-state@1.1.0(@types/react@19.2.2)(react@19.3.0-canary-b546603b-20260121)': dependencies: - '@radix-ui/react-use-callback-ref': 1.1.0(@types/react@19.2.2)(react@19.3.0-canary-d2908752-20260119) - react: 19.3.0-canary-d2908752-20260119 + '@radix-ui/react-use-callback-ref': 1.1.0(@types/react@19.2.2)(react@19.3.0-canary-b546603b-20260121) + react: 19.3.0-canary-b546603b-20260121 optionalDependencies: '@types/react': 19.2.2 - '@radix-ui/react-use-controllable-state@1.2.2(@types/react@19.2.2)(react@19.3.0-canary-d2908752-20260119)': + '@radix-ui/react-use-controllable-state@1.2.2(@types/react@19.2.2)(react@19.3.0-canary-b546603b-20260121)': dependencies: - '@radix-ui/react-use-effect-event': 0.0.2(@types/react@19.2.2)(react@19.3.0-canary-d2908752-20260119) - '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.2.2)(react@19.3.0-canary-d2908752-20260119) - react: 19.3.0-canary-d2908752-20260119 + '@radix-ui/react-use-effect-event': 0.0.2(@types/react@19.2.2)(react@19.3.0-canary-b546603b-20260121) + '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.2.2)(react@19.3.0-canary-b546603b-20260121) + react: 19.3.0-canary-b546603b-20260121 optionalDependencies: '@types/react': 19.2.2 - '@radix-ui/react-use-effect-event@0.0.2(@types/react@19.2.2)(react@19.3.0-canary-d2908752-20260119)': + '@radix-ui/react-use-effect-event@0.0.2(@types/react@19.2.2)(react@19.3.0-canary-b546603b-20260121)': dependencies: - '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.2.2)(react@19.3.0-canary-d2908752-20260119) - react: 19.3.0-canary-d2908752-20260119 + '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.2.2)(react@19.3.0-canary-b546603b-20260121) + react: 19.3.0-canary-b546603b-20260121 optionalDependencies: '@types/react': 19.2.2 - '@radix-ui/react-use-escape-keydown@1.1.0(@types/react@19.2.2)(react@19.3.0-canary-d2908752-20260119)': + '@radix-ui/react-use-escape-keydown@1.1.0(@types/react@19.2.2)(react@19.3.0-canary-b546603b-20260121)': dependencies: - '@radix-ui/react-use-callback-ref': 1.1.0(@types/react@19.2.2)(react@19.3.0-canary-d2908752-20260119) - react: 19.3.0-canary-d2908752-20260119 + '@radix-ui/react-use-callback-ref': 1.1.0(@types/react@19.2.2)(react@19.3.0-canary-b546603b-20260121) + react: 19.3.0-canary-b546603b-20260121 optionalDependencies: '@types/react': 19.2.2 - '@radix-ui/react-use-escape-keydown@1.1.1(@types/react@19.2.2)(react@19.3.0-canary-d2908752-20260119)': + '@radix-ui/react-use-escape-keydown@1.1.1(@types/react@19.2.2)(react@19.3.0-canary-b546603b-20260121)': dependencies: - '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@19.2.2)(react@19.3.0-canary-d2908752-20260119) - react: 19.3.0-canary-d2908752-20260119 + '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@19.2.2)(react@19.3.0-canary-b546603b-20260121) + react: 19.3.0-canary-b546603b-20260121 optionalDependencies: '@types/react': 19.2.2 - '@radix-ui/react-use-layout-effect@1.1.0(@types/react@19.2.2)(react@19.3.0-canary-d2908752-20260119)': + '@radix-ui/react-use-layout-effect@1.1.0(@types/react@19.2.2)(react@19.3.0-canary-b546603b-20260121)': dependencies: - react: 19.3.0-canary-d2908752-20260119 + react: 19.3.0-canary-b546603b-20260121 optionalDependencies: '@types/react': 19.2.2 - '@radix-ui/react-use-layout-effect@1.1.1(@types/react@19.2.2)(react@19.3.0-canary-d2908752-20260119)': + '@radix-ui/react-use-layout-effect@1.1.1(@types/react@19.2.2)(react@19.3.0-canary-b546603b-20260121)': dependencies: - react: 19.3.0-canary-d2908752-20260119 + react: 19.3.0-canary-b546603b-20260121 optionalDependencies: '@types/react': 19.2.2 - '@radix-ui/react-use-previous@1.1.1(@types/react@19.2.2)(react@19.3.0-canary-d2908752-20260119)': + '@radix-ui/react-use-previous@1.1.1(@types/react@19.2.2)(react@19.3.0-canary-b546603b-20260121)': dependencies: - react: 19.3.0-canary-d2908752-20260119 + react: 19.3.0-canary-b546603b-20260121 optionalDependencies: '@types/react': 19.2.2 - '@radix-ui/react-use-rect@1.1.0(@types/react@19.2.2)(react@19.3.0-canary-d2908752-20260119)': + '@radix-ui/react-use-rect@1.1.0(@types/react@19.2.2)(react@19.3.0-canary-b546603b-20260121)': dependencies: '@radix-ui/rect': 1.1.0 - react: 19.3.0-canary-d2908752-20260119 + react: 19.3.0-canary-b546603b-20260121 optionalDependencies: '@types/react': 19.2.2 - '@radix-ui/react-use-rect@1.1.1(@types/react@19.2.2)(react@19.3.0-canary-d2908752-20260119)': + '@radix-ui/react-use-rect@1.1.1(@types/react@19.2.2)(react@19.3.0-canary-b546603b-20260121)': dependencies: '@radix-ui/rect': 1.1.1 - react: 19.3.0-canary-d2908752-20260119 + react: 19.3.0-canary-b546603b-20260121 optionalDependencies: '@types/react': 19.2.2 - '@radix-ui/react-use-size@1.1.0(@types/react@19.2.2)(react@19.3.0-canary-d2908752-20260119)': + '@radix-ui/react-use-size@1.1.0(@types/react@19.2.2)(react@19.3.0-canary-b546603b-20260121)': dependencies: - '@radix-ui/react-use-layout-effect': 1.1.0(@types/react@19.2.2)(react@19.3.0-canary-d2908752-20260119) - react: 19.3.0-canary-d2908752-20260119 + '@radix-ui/react-use-layout-effect': 1.1.0(@types/react@19.2.2)(react@19.3.0-canary-b546603b-20260121) + react: 19.3.0-canary-b546603b-20260121 optionalDependencies: '@types/react': 19.2.2 - '@radix-ui/react-use-size@1.1.1(@types/react@19.2.2)(react@19.3.0-canary-d2908752-20260119)': + '@radix-ui/react-use-size@1.1.1(@types/react@19.2.2)(react@19.3.0-canary-b546603b-20260121)': dependencies: - '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.2.2)(react@19.3.0-canary-d2908752-20260119) - react: 19.3.0-canary-d2908752-20260119 + '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.2.2)(react@19.3.0-canary-b546603b-20260121) + react: 19.3.0-canary-b546603b-20260121 optionalDependencies: '@types/react': 19.2.2 - '@radix-ui/react-visually-hidden@1.1.0(@types/react-dom@19.2.1(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.3.0-canary-d2908752-20260119(react@19.3.0-canary-d2908752-20260119))(react@19.3.0-canary-d2908752-20260119)': + '@radix-ui/react-visually-hidden@1.1.0(@types/react-dom@19.2.1(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.3.0-canary-b546603b-20260121(react@19.3.0-canary-b546603b-20260121))(react@19.3.0-canary-b546603b-20260121)': dependencies: - '@radix-ui/react-primitive': 2.0.0(@types/react-dom@19.2.1(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.3.0-canary-d2908752-20260119(react@19.3.0-canary-d2908752-20260119))(react@19.3.0-canary-d2908752-20260119) - react: 19.3.0-canary-d2908752-20260119 - react-dom: 19.3.0-canary-d2908752-20260119(react@19.3.0-canary-d2908752-20260119) + '@radix-ui/react-primitive': 2.0.0(@types/react-dom@19.2.1(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.3.0-canary-b546603b-20260121(react@19.3.0-canary-b546603b-20260121))(react@19.3.0-canary-b546603b-20260121) + react: 19.3.0-canary-b546603b-20260121 + react-dom: 19.3.0-canary-b546603b-20260121(react@19.3.0-canary-b546603b-20260121) optionalDependencies: '@types/react': 19.2.2 '@types/react-dom': 19.2.1(@types/react@19.2.2) - '@radix-ui/react-visually-hidden@1.2.3(@types/react-dom@19.2.1(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.3.0-canary-d2908752-20260119(react@19.3.0-canary-d2908752-20260119))(react@19.3.0-canary-d2908752-20260119)': + '@radix-ui/react-visually-hidden@1.2.3(@types/react-dom@19.2.1(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.3.0-canary-b546603b-20260121(react@19.3.0-canary-b546603b-20260121))(react@19.3.0-canary-b546603b-20260121)': dependencies: - '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.1(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.3.0-canary-d2908752-20260119(react@19.3.0-canary-d2908752-20260119))(react@19.3.0-canary-d2908752-20260119) - react: 19.3.0-canary-d2908752-20260119 - react-dom: 19.3.0-canary-d2908752-20260119(react@19.3.0-canary-d2908752-20260119) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.1(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.3.0-canary-b546603b-20260121(react@19.3.0-canary-b546603b-20260121))(react@19.3.0-canary-b546603b-20260121) + react: 19.3.0-canary-b546603b-20260121 + react-dom: 19.3.0-canary-b546603b-20260121(react@19.3.0-canary-b546603b-20260121) optionalDependencies: '@types/react': 19.2.2 '@types/react-dom': 19.2.1(@types/react@19.2.2) @@ -23345,12 +23345,12 @@ snapshots: '@storybook/addon-docs@8.6.0(@types/react@19.2.2)(storybook@8.6.0(prettier@3.6.2))': dependencies: - '@mdx-js/react': 3.1.0(@types/react@19.2.2)(react@19.3.0-canary-d2908752-20260119) - '@storybook/blocks': 8.6.0(react-dom@19.3.0-canary-d2908752-20260119(react@19.3.0-canary-d2908752-20260119))(react@19.3.0-canary-d2908752-20260119)(storybook@8.6.0(prettier@3.6.2)) + '@mdx-js/react': 3.1.0(@types/react@19.2.2)(react@19.3.0-canary-b546603b-20260121) + '@storybook/blocks': 8.6.0(react-dom@19.3.0-canary-b546603b-20260121(react@19.3.0-canary-b546603b-20260121))(react@19.3.0-canary-b546603b-20260121)(storybook@8.6.0(prettier@3.6.2)) '@storybook/csf-plugin': 8.6.0(storybook@8.6.0(prettier@3.6.2)) - '@storybook/react-dom-shim': 8.6.0(react-dom@19.3.0-canary-d2908752-20260119(react@19.3.0-canary-d2908752-20260119))(react@19.3.0-canary-d2908752-20260119)(storybook@8.6.0(prettier@3.6.2)) - react: 19.3.0-canary-d2908752-20260119 - react-dom: 19.3.0-canary-d2908752-20260119(react@19.3.0-canary-d2908752-20260119) + '@storybook/react-dom-shim': 8.6.0(react-dom@19.3.0-canary-b546603b-20260121(react@19.3.0-canary-b546603b-20260121))(react@19.3.0-canary-b546603b-20260121)(storybook@8.6.0(prettier@3.6.2)) + react: 19.3.0-canary-b546603b-20260121 + react-dom: 19.3.0-canary-b546603b-20260121(react@19.3.0-canary-b546603b-20260121) storybook: 8.6.0(prettier@3.6.2) ts-dedent: 2.2.0 transitivePeerDependencies: @@ -23415,14 +23415,14 @@ snapshots: - '@swc/helpers' - webpack - '@storybook/blocks@8.6.0(react-dom@19.3.0-canary-d2908752-20260119(react@19.3.0-canary-d2908752-20260119))(react@19.3.0-canary-d2908752-20260119)(storybook@8.6.0(prettier@3.6.2))': + '@storybook/blocks@8.6.0(react-dom@19.3.0-canary-b546603b-20260121(react@19.3.0-canary-b546603b-20260121))(react@19.3.0-canary-b546603b-20260121)(storybook@8.6.0(prettier@3.6.2))': dependencies: - '@storybook/icons': 1.3.0(react-dom@19.3.0-canary-d2908752-20260119(react@19.3.0-canary-d2908752-20260119))(react@19.3.0-canary-d2908752-20260119) + '@storybook/icons': 1.3.0(react-dom@19.3.0-canary-b546603b-20260121(react@19.3.0-canary-b546603b-20260121))(react@19.3.0-canary-b546603b-20260121) storybook: 8.6.0(prettier@3.6.2) ts-dedent: 2.2.0 optionalDependencies: - react: 19.3.0-canary-d2908752-20260119 - react-dom: 19.3.0-canary-d2908752-20260119(react@19.3.0-canary-d2908752-20260119) + react: 19.3.0-canary-b546603b-20260121 + react-dom: 19.3.0-canary-b546603b-20260121(react@19.3.0-canary-b546603b-20260121) '@storybook/builder-webpack5@8.6.0(@rspack/core@1.6.7(@swc/helpers@0.5.15))(@swc/core@1.11.24(@swc/helpers@0.5.15))(esbuild@0.25.9)(storybook@8.6.0(prettier@3.6.2))(typescript@5.9.2)': dependencies: @@ -23501,10 +23501,10 @@ snapshots: '@storybook/global@5.0.0': {} - '@storybook/icons@1.3.0(react-dom@19.3.0-canary-d2908752-20260119(react@19.3.0-canary-d2908752-20260119))(react@19.3.0-canary-d2908752-20260119)': + '@storybook/icons@1.3.0(react-dom@19.3.0-canary-b546603b-20260121(react@19.3.0-canary-b546603b-20260121))(react@19.3.0-canary-b546603b-20260121)': dependencies: - react: 19.3.0-canary-d2908752-20260119 - react-dom: 19.3.0-canary-d2908752-20260119(react@19.3.0-canary-d2908752-20260119) + react: 19.3.0-canary-b546603b-20260121 + react-dom: 19.3.0-canary-b546603b-20260121(react@19.3.0-canary-b546603b-20260121) '@storybook/instrumenter@8.6.0(storybook@8.6.0(prettier@3.6.2))': dependencies: @@ -23516,17 +23516,17 @@ snapshots: dependencies: storybook: 8.6.0(prettier@3.6.2) - '@storybook/preset-react-webpack@8.6.0(@storybook/test@8.6.0(storybook@8.6.0(prettier@3.6.2)))(@swc/core@1.11.24(@swc/helpers@0.5.15))(esbuild@0.25.9)(react-dom@19.3.0-canary-d2908752-20260119(react@19.3.0-canary-d2908752-20260119))(react@19.3.0-canary-d2908752-20260119)(storybook@8.6.0(prettier@3.6.2))(typescript@5.9.2)': + '@storybook/preset-react-webpack@8.6.0(@storybook/test@8.6.0(storybook@8.6.0(prettier@3.6.2)))(@swc/core@1.11.24(@swc/helpers@0.5.15))(esbuild@0.25.9)(react-dom@19.3.0-canary-b546603b-20260121(react@19.3.0-canary-b546603b-20260121))(react@19.3.0-canary-b546603b-20260121)(storybook@8.6.0(prettier@3.6.2))(typescript@5.9.2)': dependencies: '@storybook/core-webpack': 8.6.0(storybook@8.6.0(prettier@3.6.2)) - '@storybook/react': 8.6.0(@storybook/test@8.6.0(storybook@8.6.0(prettier@3.6.2)))(react-dom@19.3.0-canary-d2908752-20260119(react@19.3.0-canary-d2908752-20260119))(react@19.3.0-canary-d2908752-20260119)(storybook@8.6.0(prettier@3.6.2))(typescript@5.9.2) + '@storybook/react': 8.6.0(@storybook/test@8.6.0(storybook@8.6.0(prettier@3.6.2)))(react-dom@19.3.0-canary-b546603b-20260121(react@19.3.0-canary-b546603b-20260121))(react@19.3.0-canary-b546603b-20260121)(storybook@8.6.0(prettier@3.6.2))(typescript@5.9.2) '@storybook/react-docgen-typescript-plugin': 1.0.6--canary.9.0c3f3b7.0(typescript@5.9.2)(webpack@5.98.0(@swc/core@1.11.24(@swc/helpers@0.5.15))(esbuild@0.25.9)) '@types/semver': 7.5.6 find-up: 5.0.0 magic-string: 0.30.19 - react: 19.3.0-canary-d2908752-20260119 + react: 19.3.0-canary-b546603b-20260121 react-docgen: 7.1.0 - react-dom: 19.3.0-canary-d2908752-20260119(react@19.3.0-canary-d2908752-20260119) + react-dom: 19.3.0-canary-b546603b-20260121(react@19.3.0-canary-b546603b-20260121) resolve: 1.22.10 semver: 7.6.3 storybook: 8.6.0(prettier@3.6.2) @@ -23560,19 +23560,19 @@ snapshots: transitivePeerDependencies: - supports-color - '@storybook/react-dom-shim@8.6.0(react-dom@19.3.0-canary-d2908752-20260119(react@19.3.0-canary-d2908752-20260119))(react@19.3.0-canary-d2908752-20260119)(storybook@8.6.0(prettier@3.6.2))': + '@storybook/react-dom-shim@8.6.0(react-dom@19.3.0-canary-b546603b-20260121(react@19.3.0-canary-b546603b-20260121))(react@19.3.0-canary-b546603b-20260121)(storybook@8.6.0(prettier@3.6.2))': dependencies: - react: 19.3.0-canary-d2908752-20260119 - react-dom: 19.3.0-canary-d2908752-20260119(react@19.3.0-canary-d2908752-20260119) + react: 19.3.0-canary-b546603b-20260121 + react-dom: 19.3.0-canary-b546603b-20260121(react@19.3.0-canary-b546603b-20260121) storybook: 8.6.0(prettier@3.6.2) - '@storybook/react-webpack5@8.6.0(@rspack/core@1.6.7(@swc/helpers@0.5.15))(@storybook/test@8.6.0(storybook@8.6.0(prettier@3.6.2)))(@swc/core@1.11.24(@swc/helpers@0.5.15))(esbuild@0.25.9)(react-dom@19.3.0-canary-d2908752-20260119(react@19.3.0-canary-d2908752-20260119))(react@19.3.0-canary-d2908752-20260119)(storybook@8.6.0(prettier@3.6.2))(typescript@5.9.2)': + '@storybook/react-webpack5@8.6.0(@rspack/core@1.6.7(@swc/helpers@0.5.15))(@storybook/test@8.6.0(storybook@8.6.0(prettier@3.6.2)))(@swc/core@1.11.24(@swc/helpers@0.5.15))(esbuild@0.25.9)(react-dom@19.3.0-canary-b546603b-20260121(react@19.3.0-canary-b546603b-20260121))(react@19.3.0-canary-b546603b-20260121)(storybook@8.6.0(prettier@3.6.2))(typescript@5.9.2)': dependencies: '@storybook/builder-webpack5': 8.6.0(@rspack/core@1.6.7(@swc/helpers@0.5.15))(@swc/core@1.11.24(@swc/helpers@0.5.15))(esbuild@0.25.9)(storybook@8.6.0(prettier@3.6.2))(typescript@5.9.2) - '@storybook/preset-react-webpack': 8.6.0(@storybook/test@8.6.0(storybook@8.6.0(prettier@3.6.2)))(@swc/core@1.11.24(@swc/helpers@0.5.15))(esbuild@0.25.9)(react-dom@19.3.0-canary-d2908752-20260119(react@19.3.0-canary-d2908752-20260119))(react@19.3.0-canary-d2908752-20260119)(storybook@8.6.0(prettier@3.6.2))(typescript@5.9.2) - '@storybook/react': 8.6.0(@storybook/test@8.6.0(storybook@8.6.0(prettier@3.6.2)))(react-dom@19.3.0-canary-d2908752-20260119(react@19.3.0-canary-d2908752-20260119))(react@19.3.0-canary-d2908752-20260119)(storybook@8.6.0(prettier@3.6.2))(typescript@5.9.2) - react: 19.3.0-canary-d2908752-20260119 - react-dom: 19.3.0-canary-d2908752-20260119(react@19.3.0-canary-d2908752-20260119) + '@storybook/preset-react-webpack': 8.6.0(@storybook/test@8.6.0(storybook@8.6.0(prettier@3.6.2)))(@swc/core@1.11.24(@swc/helpers@0.5.15))(esbuild@0.25.9)(react-dom@19.3.0-canary-b546603b-20260121(react@19.3.0-canary-b546603b-20260121))(react@19.3.0-canary-b546603b-20260121)(storybook@8.6.0(prettier@3.6.2))(typescript@5.9.2) + '@storybook/react': 8.6.0(@storybook/test@8.6.0(storybook@8.6.0(prettier@3.6.2)))(react-dom@19.3.0-canary-b546603b-20260121(react@19.3.0-canary-b546603b-20260121))(react@19.3.0-canary-b546603b-20260121)(storybook@8.6.0(prettier@3.6.2))(typescript@5.9.2) + react: 19.3.0-canary-b546603b-20260121 + react-dom: 19.3.0-canary-b546603b-20260121(react@19.3.0-canary-b546603b-20260121) storybook: 8.6.0(prettier@3.6.2) optionalDependencies: typescript: 5.9.2 @@ -23585,16 +23585,16 @@ snapshots: - uglify-js - webpack-cli - '@storybook/react@8.6.0(@storybook/test@8.6.0(storybook@8.6.0(prettier@3.6.2)))(react-dom@19.3.0-canary-d2908752-20260119(react@19.3.0-canary-d2908752-20260119))(react@19.3.0-canary-d2908752-20260119)(storybook@8.6.0(prettier@3.6.2))(typescript@5.9.2)': + '@storybook/react@8.6.0(@storybook/test@8.6.0(storybook@8.6.0(prettier@3.6.2)))(react-dom@19.3.0-canary-b546603b-20260121(react@19.3.0-canary-b546603b-20260121))(react@19.3.0-canary-b546603b-20260121)(storybook@8.6.0(prettier@3.6.2))(typescript@5.9.2)': dependencies: '@storybook/components': 8.6.0(storybook@8.6.0(prettier@3.6.2)) '@storybook/global': 5.0.0 '@storybook/manager-api': 8.6.0(storybook@8.6.0(prettier@3.6.2)) '@storybook/preview-api': 8.6.0(storybook@8.6.0(prettier@3.6.2)) - '@storybook/react-dom-shim': 8.6.0(react-dom@19.3.0-canary-d2908752-20260119(react@19.3.0-canary-d2908752-20260119))(react@19.3.0-canary-d2908752-20260119)(storybook@8.6.0(prettier@3.6.2)) + '@storybook/react-dom-shim': 8.6.0(react-dom@19.3.0-canary-b546603b-20260121(react@19.3.0-canary-b546603b-20260121))(react@19.3.0-canary-b546603b-20260121)(storybook@8.6.0(prettier@3.6.2)) '@storybook/theming': 8.6.0(storybook@8.6.0(prettier@3.6.2)) - react: 19.3.0-canary-d2908752-20260119 - react-dom: 19.3.0-canary-d2908752-20260119(react@19.3.0-canary-d2908752-20260119) + react: 19.3.0-canary-b546603b-20260121 + react-dom: 19.3.0-canary-b546603b-20260121(react@19.3.0-canary-b546603b-20260121) storybook: 8.6.0(prettier@3.6.2) optionalDependencies: '@storybook/test': 8.6.0(storybook@8.6.0(prettier@3.6.2)) @@ -23872,13 +23872,13 @@ snapshots: lodash: 4.17.21 redent: 3.0.0 - '@testing-library/react@15.0.7(@types/react@19.2.2)(react-dom@19.3.0-canary-d2908752-20260119(react@19.3.0-canary-d2908752-20260119))(react@19.3.0-canary-d2908752-20260119)': + '@testing-library/react@15.0.7(@types/react@19.2.2)(react-dom@19.3.0-canary-b546603b-20260121(react@19.3.0-canary-b546603b-20260121))(react@19.3.0-canary-b546603b-20260121)': dependencies: '@babel/runtime': 7.27.0 '@testing-library/dom': 10.1.0 '@types/react-dom': 19.2.1(@types/react@19.2.2) - react: 19.3.0-canary-d2908752-20260119 - react-dom: 19.3.0-canary-d2908752-20260119(react@19.3.0-canary-d2908752-20260119) + react: 19.3.0-canary-b546603b-20260121 + react-dom: 19.3.0-canary-b546603b-20260121(react@19.3.0-canary-b546603b-20260121) optionalDependencies: '@types/react': 19.2.2 @@ -26116,14 +26116,14 @@ snapshots: cmd-shim@7.0.0: {} - cmdk@1.0.4(@types/react-dom@19.2.1(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.3.0-canary-d2908752-20260119(react@19.3.0-canary-d2908752-20260119))(react@19.3.0-canary-d2908752-20260119): + cmdk@1.0.4(@types/react-dom@19.2.1(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.3.0-canary-b546603b-20260121(react@19.3.0-canary-b546603b-20260121))(react@19.3.0-canary-b546603b-20260121): dependencies: - '@radix-ui/react-dialog': 1.1.4(@types/react-dom@19.2.1(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.3.0-canary-d2908752-20260119(react@19.3.0-canary-d2908752-20260119))(react@19.3.0-canary-d2908752-20260119) - '@radix-ui/react-id': 1.1.1(@types/react@19.2.2)(react@19.3.0-canary-d2908752-20260119) - '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.1(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.3.0-canary-d2908752-20260119(react@19.3.0-canary-d2908752-20260119))(react@19.3.0-canary-d2908752-20260119) - react: 19.3.0-canary-d2908752-20260119 - react-dom: 19.3.0-canary-d2908752-20260119(react@19.3.0-canary-d2908752-20260119) - use-sync-external-store: 1.5.0(react@19.3.0-canary-d2908752-20260119) + '@radix-ui/react-dialog': 1.1.4(@types/react-dom@19.2.1(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.3.0-canary-b546603b-20260121(react@19.3.0-canary-b546603b-20260121))(react@19.3.0-canary-b546603b-20260121) + '@radix-ui/react-id': 1.1.1(@types/react@19.2.2)(react@19.3.0-canary-b546603b-20260121) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.1(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.3.0-canary-b546603b-20260121(react@19.3.0-canary-b546603b-20260121))(react@19.3.0-canary-b546603b-20260121) + react: 19.3.0-canary-b546603b-20260121 + react-dom: 19.3.0-canary-b546603b-20260121(react@19.3.0-canary-b546603b-20260121) + use-sync-external-store: 1.5.0(react@19.3.0-canary-b546603b-20260121) transitivePeerDependencies: - '@types/react' - '@types/react-dom' @@ -28157,7 +28157,7 @@ snapshots: - bluebird - supports-color - eslint-plugin-react-hooks@0.0.0-experimental-d2908752-20260119(eslint@9.37.0(jiti@2.5.1)): + eslint-plugin-react-hooks@0.0.0-experimental-b546603b-20260121(eslint@9.37.0(jiti@2.5.1)): dependencies: '@babel/core': 7.26.10 '@babel/parser': 7.27.0 @@ -29115,7 +29115,7 @@ snapshots: fsevents@2.3.3: optional: true - fumadocs-core@15.7.12(@types/react@19.2.2)(next@15.5.8(@babel/core@7.26.10)(@opentelemetry/api@1.6.0)(@playwright/test@1.51.1)(babel-plugin-macros@3.1.0)(babel-plugin-react-compiler@0.0.0-experimental-3fde738-20250918)(react-dom@19.3.0-canary-d2908752-20260119(react@19.3.0-canary-d2908752-20260119))(react@19.3.0-canary-d2908752-20260119)(sass@1.77.8))(react-dom@19.3.0-canary-d2908752-20260119(react@19.3.0-canary-d2908752-20260119))(react@19.3.0-canary-d2908752-20260119): + fumadocs-core@15.7.12(@types/react@19.2.2)(next@15.5.8(@babel/core@7.26.10)(@opentelemetry/api@1.6.0)(@playwright/test@1.51.1)(babel-plugin-macros@3.1.0)(babel-plugin-react-compiler@0.0.0-experimental-3fde738-20250918)(react-dom@19.3.0-canary-b546603b-20260121(react@19.3.0-canary-b546603b-20260121))(react@19.3.0-canary-b546603b-20260121)(sass@1.77.8))(react-dom@19.3.0-canary-b546603b-20260121(react@19.3.0-canary-b546603b-20260121))(react@19.3.0-canary-b546603b-20260121): dependencies: '@formatjs/intl-localematcher': 0.6.1 '@orama/orama': 3.1.13 @@ -29127,7 +29127,7 @@ snapshots: image-size: 2.0.2 negotiator: 1.0.0 npm-to-yarn: 3.0.1 - react-remove-scroll: 2.7.1(@types/react@19.2.2)(react@19.3.0-canary-d2908752-20260119) + react-remove-scroll: 2.7.1(@types/react@19.2.2)(react@19.3.0-canary-b546603b-20260121) remark: 15.0.1 remark-gfm: 4.0.1 remark-rehype: 11.1.2 @@ -29136,20 +29136,20 @@ snapshots: unist-util-visit: 5.0.0 optionalDependencies: '@types/react': 19.2.2 - next: 15.5.8(@babel/core@7.26.10)(@opentelemetry/api@1.6.0)(@playwright/test@1.51.1)(babel-plugin-macros@3.1.0)(babel-plugin-react-compiler@0.0.0-experimental-3fde738-20250918)(react-dom@19.3.0-canary-d2908752-20260119(react@19.3.0-canary-d2908752-20260119))(react@19.3.0-canary-d2908752-20260119)(sass@1.77.8) - react: 19.3.0-canary-d2908752-20260119 - react-dom: 19.3.0-canary-d2908752-20260119(react@19.3.0-canary-d2908752-20260119) + next: 15.5.8(@babel/core@7.26.10)(@opentelemetry/api@1.6.0)(@playwright/test@1.51.1)(babel-plugin-macros@3.1.0)(babel-plugin-react-compiler@0.0.0-experimental-3fde738-20250918)(react-dom@19.3.0-canary-b546603b-20260121(react@19.3.0-canary-b546603b-20260121))(react@19.3.0-canary-b546603b-20260121)(sass@1.77.8) + react: 19.3.0-canary-b546603b-20260121 + react-dom: 19.3.0-canary-b546603b-20260121(react@19.3.0-canary-b546603b-20260121) transitivePeerDependencies: - supports-color - fumadocs-mdx@11.10.0(fumadocs-core@15.7.12(@types/react@19.2.2)(next@15.5.8(@babel/core@7.26.10)(@opentelemetry/api@1.6.0)(@playwright/test@1.51.1)(babel-plugin-macros@3.1.0)(babel-plugin-react-compiler@0.0.0-experimental-3fde738-20250918)(react-dom@19.3.0-canary-d2908752-20260119(react@19.3.0-canary-d2908752-20260119))(react@19.3.0-canary-d2908752-20260119)(sass@1.77.8))(react-dom@19.3.0-canary-d2908752-20260119(react@19.3.0-canary-d2908752-20260119))(react@19.3.0-canary-d2908752-20260119))(next@15.5.8(@babel/core@7.26.10)(@opentelemetry/api@1.6.0)(@playwright/test@1.51.1)(babel-plugin-macros@3.1.0)(babel-plugin-react-compiler@0.0.0-experimental-3fde738-20250918)(react-dom@19.3.0-canary-d2908752-20260119(react@19.3.0-canary-d2908752-20260119))(react@19.3.0-canary-d2908752-20260119)(sass@1.77.8))(react@19.3.0-canary-d2908752-20260119): + fumadocs-mdx@11.10.0(fumadocs-core@15.7.12(@types/react@19.2.2)(next@15.5.8(@babel/core@7.26.10)(@opentelemetry/api@1.6.0)(@playwright/test@1.51.1)(babel-plugin-macros@3.1.0)(babel-plugin-react-compiler@0.0.0-experimental-3fde738-20250918)(react-dom@19.3.0-canary-b546603b-20260121(react@19.3.0-canary-b546603b-20260121))(react@19.3.0-canary-b546603b-20260121)(sass@1.77.8))(react-dom@19.3.0-canary-b546603b-20260121(react@19.3.0-canary-b546603b-20260121))(react@19.3.0-canary-b546603b-20260121))(next@15.5.8(@babel/core@7.26.10)(@opentelemetry/api@1.6.0)(@playwright/test@1.51.1)(babel-plugin-macros@3.1.0)(babel-plugin-react-compiler@0.0.0-experimental-3fde738-20250918)(react-dom@19.3.0-canary-b546603b-20260121(react@19.3.0-canary-b546603b-20260121))(react@19.3.0-canary-b546603b-20260121)(sass@1.77.8))(react@19.3.0-canary-b546603b-20260121): dependencies: '@mdx-js/mdx': 3.1.1 '@standard-schema/spec': 1.0.0 chokidar: 4.0.3 esbuild: 0.25.9 estree-util-value-to-estree: 3.5.0 - fumadocs-core: 15.7.12(@types/react@19.2.2)(next@15.5.8(@babel/core@7.26.10)(@opentelemetry/api@1.6.0)(@playwright/test@1.51.1)(babel-plugin-macros@3.1.0)(babel-plugin-react-compiler@0.0.0-experimental-3fde738-20250918)(react-dom@19.3.0-canary-d2908752-20260119(react@19.3.0-canary-d2908752-20260119))(react@19.3.0-canary-d2908752-20260119)(sass@1.77.8))(react-dom@19.3.0-canary-d2908752-20260119(react@19.3.0-canary-d2908752-20260119))(react@19.3.0-canary-d2908752-20260119) + fumadocs-core: 15.7.12(@types/react@19.2.2)(next@15.5.8(@babel/core@7.26.10)(@opentelemetry/api@1.6.0)(@playwright/test@1.51.1)(babel-plugin-macros@3.1.0)(babel-plugin-react-compiler@0.0.0-experimental-3fde738-20250918)(react-dom@19.3.0-canary-b546603b-20260121(react@19.3.0-canary-b546603b-20260121))(react@19.3.0-canary-b546603b-20260121)(sass@1.77.8))(react-dom@19.3.0-canary-b546603b-20260121(react@19.3.0-canary-b546603b-20260121))(react@19.3.0-canary-b546603b-20260121) js-yaml: 4.1.0 lru-cache: 11.2.1 picocolors: 1.1.1 @@ -29161,36 +29161,36 @@ snapshots: unist-util-visit: 5.0.0 zod: 4.1.13 optionalDependencies: - next: 15.5.8(@babel/core@7.26.10)(@opentelemetry/api@1.6.0)(@playwright/test@1.51.1)(babel-plugin-macros@3.1.0)(babel-plugin-react-compiler@0.0.0-experimental-3fde738-20250918)(react-dom@19.3.0-canary-d2908752-20260119(react@19.3.0-canary-d2908752-20260119))(react@19.3.0-canary-d2908752-20260119)(sass@1.77.8) - react: 19.3.0-canary-d2908752-20260119 + next: 15.5.8(@babel/core@7.26.10)(@opentelemetry/api@1.6.0)(@playwright/test@1.51.1)(babel-plugin-macros@3.1.0)(babel-plugin-react-compiler@0.0.0-experimental-3fde738-20250918)(react-dom@19.3.0-canary-b546603b-20260121(react@19.3.0-canary-b546603b-20260121))(react@19.3.0-canary-b546603b-20260121)(sass@1.77.8) + react: 19.3.0-canary-b546603b-20260121 transitivePeerDependencies: - supports-color - fumadocs-ui@15.7.12(@types/react-dom@19.2.1(@types/react@19.2.2))(@types/react@19.2.2)(next@15.5.8(@babel/core@7.26.10)(@opentelemetry/api@1.6.0)(@playwright/test@1.51.1)(babel-plugin-macros@3.1.0)(babel-plugin-react-compiler@0.0.0-experimental-3fde738-20250918)(react-dom@19.3.0-canary-d2908752-20260119(react@19.3.0-canary-d2908752-20260119))(react@19.3.0-canary-d2908752-20260119)(sass@1.77.8))(react-dom@19.3.0-canary-d2908752-20260119(react@19.3.0-canary-d2908752-20260119))(react@19.3.0-canary-d2908752-20260119)(tailwindcss@4.1.13): - dependencies: - '@radix-ui/react-accordion': 1.2.12(@types/react-dom@19.2.1(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.3.0-canary-d2908752-20260119(react@19.3.0-canary-d2908752-20260119))(react@19.3.0-canary-d2908752-20260119) - '@radix-ui/react-collapsible': 1.1.12(@types/react-dom@19.2.1(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.3.0-canary-d2908752-20260119(react@19.3.0-canary-d2908752-20260119))(react@19.3.0-canary-d2908752-20260119) - '@radix-ui/react-dialog': 1.1.15(@types/react-dom@19.2.1(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.3.0-canary-d2908752-20260119(react@19.3.0-canary-d2908752-20260119))(react@19.3.0-canary-d2908752-20260119) - '@radix-ui/react-direction': 1.1.1(@types/react@19.2.2)(react@19.3.0-canary-d2908752-20260119) - '@radix-ui/react-navigation-menu': 1.2.14(@types/react-dom@19.2.1(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.3.0-canary-d2908752-20260119(react@19.3.0-canary-d2908752-20260119))(react@19.3.0-canary-d2908752-20260119) - '@radix-ui/react-popover': 1.1.15(@types/react-dom@19.2.1(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.3.0-canary-d2908752-20260119(react@19.3.0-canary-d2908752-20260119))(react@19.3.0-canary-d2908752-20260119) - '@radix-ui/react-presence': 1.1.5(@types/react-dom@19.2.1(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.3.0-canary-d2908752-20260119(react@19.3.0-canary-d2908752-20260119))(react@19.3.0-canary-d2908752-20260119) - '@radix-ui/react-scroll-area': 1.2.10(@types/react-dom@19.2.1(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.3.0-canary-d2908752-20260119(react@19.3.0-canary-d2908752-20260119))(react@19.3.0-canary-d2908752-20260119) - '@radix-ui/react-slot': 1.2.3(@types/react@19.2.2)(react@19.3.0-canary-d2908752-20260119) - '@radix-ui/react-tabs': 1.1.13(@types/react-dom@19.2.1(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.3.0-canary-d2908752-20260119(react@19.3.0-canary-d2908752-20260119))(react@19.3.0-canary-d2908752-20260119) + fumadocs-ui@15.7.12(@types/react-dom@19.2.1(@types/react@19.2.2))(@types/react@19.2.2)(next@15.5.8(@babel/core@7.26.10)(@opentelemetry/api@1.6.0)(@playwright/test@1.51.1)(babel-plugin-macros@3.1.0)(babel-plugin-react-compiler@0.0.0-experimental-3fde738-20250918)(react-dom@19.3.0-canary-b546603b-20260121(react@19.3.0-canary-b546603b-20260121))(react@19.3.0-canary-b546603b-20260121)(sass@1.77.8))(react-dom@19.3.0-canary-b546603b-20260121(react@19.3.0-canary-b546603b-20260121))(react@19.3.0-canary-b546603b-20260121)(tailwindcss@4.1.13): + dependencies: + '@radix-ui/react-accordion': 1.2.12(@types/react-dom@19.2.1(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.3.0-canary-b546603b-20260121(react@19.3.0-canary-b546603b-20260121))(react@19.3.0-canary-b546603b-20260121) + '@radix-ui/react-collapsible': 1.1.12(@types/react-dom@19.2.1(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.3.0-canary-b546603b-20260121(react@19.3.0-canary-b546603b-20260121))(react@19.3.0-canary-b546603b-20260121) + '@radix-ui/react-dialog': 1.1.15(@types/react-dom@19.2.1(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.3.0-canary-b546603b-20260121(react@19.3.0-canary-b546603b-20260121))(react@19.3.0-canary-b546603b-20260121) + '@radix-ui/react-direction': 1.1.1(@types/react@19.2.2)(react@19.3.0-canary-b546603b-20260121) + '@radix-ui/react-navigation-menu': 1.2.14(@types/react-dom@19.2.1(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.3.0-canary-b546603b-20260121(react@19.3.0-canary-b546603b-20260121))(react@19.3.0-canary-b546603b-20260121) + '@radix-ui/react-popover': 1.1.15(@types/react-dom@19.2.1(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.3.0-canary-b546603b-20260121(react@19.3.0-canary-b546603b-20260121))(react@19.3.0-canary-b546603b-20260121) + '@radix-ui/react-presence': 1.1.5(@types/react-dom@19.2.1(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.3.0-canary-b546603b-20260121(react@19.3.0-canary-b546603b-20260121))(react@19.3.0-canary-b546603b-20260121) + '@radix-ui/react-scroll-area': 1.2.10(@types/react-dom@19.2.1(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.3.0-canary-b546603b-20260121(react@19.3.0-canary-b546603b-20260121))(react@19.3.0-canary-b546603b-20260121) + '@radix-ui/react-slot': 1.2.3(@types/react@19.2.2)(react@19.3.0-canary-b546603b-20260121) + '@radix-ui/react-tabs': 1.1.13(@types/react-dom@19.2.1(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.3.0-canary-b546603b-20260121(react@19.3.0-canary-b546603b-20260121))(react@19.3.0-canary-b546603b-20260121) class-variance-authority: 0.7.1 - fumadocs-core: 15.7.12(@types/react@19.2.2)(next@15.5.8(@babel/core@7.26.10)(@opentelemetry/api@1.6.0)(@playwright/test@1.51.1)(babel-plugin-macros@3.1.0)(babel-plugin-react-compiler@0.0.0-experimental-3fde738-20250918)(react-dom@19.3.0-canary-d2908752-20260119(react@19.3.0-canary-d2908752-20260119))(react@19.3.0-canary-d2908752-20260119)(sass@1.77.8))(react-dom@19.3.0-canary-d2908752-20260119(react@19.3.0-canary-d2908752-20260119))(react@19.3.0-canary-d2908752-20260119) + fumadocs-core: 15.7.12(@types/react@19.2.2)(next@15.5.8(@babel/core@7.26.10)(@opentelemetry/api@1.6.0)(@playwright/test@1.51.1)(babel-plugin-macros@3.1.0)(babel-plugin-react-compiler@0.0.0-experimental-3fde738-20250918)(react-dom@19.3.0-canary-b546603b-20260121(react@19.3.0-canary-b546603b-20260121))(react@19.3.0-canary-b546603b-20260121)(sass@1.77.8))(react-dom@19.3.0-canary-b546603b-20260121(react@19.3.0-canary-b546603b-20260121))(react@19.3.0-canary-b546603b-20260121) lodash.merge: 4.6.2 - next-themes: 0.4.6(react-dom@19.3.0-canary-d2908752-20260119(react@19.3.0-canary-d2908752-20260119))(react@19.3.0-canary-d2908752-20260119) + next-themes: 0.4.6(react-dom@19.3.0-canary-b546603b-20260121(react@19.3.0-canary-b546603b-20260121))(react@19.3.0-canary-b546603b-20260121) postcss-selector-parser: 7.1.0 - react: 19.3.0-canary-d2908752-20260119 - react-dom: 19.3.0-canary-d2908752-20260119(react@19.3.0-canary-d2908752-20260119) - react-medium-image-zoom: 5.3.0(react-dom@19.3.0-canary-d2908752-20260119(react@19.3.0-canary-d2908752-20260119))(react@19.3.0-canary-d2908752-20260119) + react: 19.3.0-canary-b546603b-20260121 + react-dom: 19.3.0-canary-b546603b-20260121(react@19.3.0-canary-b546603b-20260121) + react-medium-image-zoom: 5.3.0(react-dom@19.3.0-canary-b546603b-20260121(react@19.3.0-canary-b546603b-20260121))(react@19.3.0-canary-b546603b-20260121) scroll-into-view-if-needed: 3.1.0 tailwind-merge: 3.3.1 optionalDependencies: '@types/react': 19.2.2 - next: 15.5.8(@babel/core@7.26.10)(@opentelemetry/api@1.6.0)(@playwright/test@1.51.1)(babel-plugin-macros@3.1.0)(babel-plugin-react-compiler@0.0.0-experimental-3fde738-20250918)(react-dom@19.3.0-canary-d2908752-20260119(react@19.3.0-canary-d2908752-20260119))(react@19.3.0-canary-d2908752-20260119)(sass@1.77.8) + next: 15.5.8(@babel/core@7.26.10)(@opentelemetry/api@1.6.0)(@playwright/test@1.51.1)(babel-plugin-macros@3.1.0)(babel-plugin-react-compiler@0.0.0-experimental-3fde738-20250918)(react-dom@19.3.0-canary-b546603b-20260121(react@19.3.0-canary-b546603b-20260121))(react@19.3.0-canary-b546603b-20260121)(sass@1.77.8) tailwindcss: 4.1.13 transitivePeerDependencies: - '@mixedbread/sdk' @@ -29862,7 +29862,7 @@ snapshots: hoist-non-react-statics@3.3.2: dependencies: - react-is: 19.3.0-canary-d2908752-20260119 + react-is: 19.3.0-canary-b546603b-20260121 homedir-polyfill@1.0.3: dependencies: @@ -32135,9 +32135,9 @@ snapshots: dependencies: react: 19.3.0-canary-fd524fe0-20251121 - lucide-react@0.554.0(react@19.3.0-canary-d2908752-20260119): + lucide-react@0.554.0(react@19.3.0-canary-b546603b-20260121): dependencies: - react: 19.3.0-canary-d2908752-20260119 + react: 19.3.0-canary-b546603b-20260121 lz-string@1.5.0: {} @@ -33495,22 +33495,22 @@ snapshots: dependencies: inherits: 2.0.4 - next-themes@0.4.6(react-dom@19.3.0-canary-d2908752-20260119(react@19.3.0-canary-d2908752-20260119))(react@19.3.0-canary-d2908752-20260119): + next-themes@0.4.6(react-dom@19.3.0-canary-b546603b-20260121(react@19.3.0-canary-b546603b-20260121))(react@19.3.0-canary-b546603b-20260121): dependencies: - react: 19.3.0-canary-d2908752-20260119 - react-dom: 19.3.0-canary-d2908752-20260119(react@19.3.0-canary-d2908752-20260119) + react: 19.3.0-canary-b546603b-20260121 + react-dom: 19.3.0-canary-b546603b-20260121(react@19.3.0-canary-b546603b-20260121) next-tick@1.0.0: {} - next@15.5.8(@babel/core@7.26.10)(@opentelemetry/api@1.6.0)(@playwright/test@1.51.1)(babel-plugin-macros@3.1.0)(babel-plugin-react-compiler@0.0.0-experimental-3fde738-20250918)(react-dom@19.3.0-canary-d2908752-20260119(react@19.3.0-canary-d2908752-20260119))(react@19.3.0-canary-d2908752-20260119)(sass@1.77.8): + next@15.5.8(@babel/core@7.26.10)(@opentelemetry/api@1.6.0)(@playwright/test@1.51.1)(babel-plugin-macros@3.1.0)(babel-plugin-react-compiler@0.0.0-experimental-3fde738-20250918)(react-dom@19.3.0-canary-b546603b-20260121(react@19.3.0-canary-b546603b-20260121))(react@19.3.0-canary-b546603b-20260121)(sass@1.77.8): dependencies: '@next/env': 15.5.8 '@swc/helpers': 0.5.15 caniuse-lite: 1.0.30001746 postcss: 8.4.31 - react: 19.3.0-canary-d2908752-20260119 - react-dom: 19.3.0-canary-d2908752-20260119(react@19.3.0-canary-d2908752-20260119) - styled-jsx: 5.1.6(@babel/core@7.26.10)(babel-plugin-macros@3.1.0)(react@19.3.0-canary-d2908752-20260119) + react: 19.3.0-canary-b546603b-20260121 + react-dom: 19.3.0-canary-b546603b-20260121(react@19.3.0-canary-b546603b-20260121) + styled-jsx: 5.1.6(@babel/core@7.26.10)(babel-plugin-macros@3.1.0)(react@19.3.0-canary-b546603b-20260121) optionalDependencies: '@next/swc-darwin-arm64': 15.5.7 '@next/swc-darwin-x64': 15.5.7 @@ -33529,15 +33529,15 @@ snapshots: - '@babel/core' - babel-plugin-macros - next@16.0.8(@babel/core@7.26.10)(@opentelemetry/api@1.6.0)(@playwright/test@1.51.1)(babel-plugin-macros@3.1.0)(babel-plugin-react-compiler@0.0.0-experimental-3fde738-20250918)(react-dom@19.3.0-canary-d2908752-20260119(react@19.3.0-canary-d2908752-20260119))(react@19.3.0-canary-d2908752-20260119)(sass@1.77.8): + next@16.0.8(@babel/core@7.26.10)(@opentelemetry/api@1.6.0)(@playwright/test@1.51.1)(babel-plugin-macros@3.1.0)(babel-plugin-react-compiler@0.0.0-experimental-3fde738-20250918)(react-dom@19.3.0-canary-b546603b-20260121(react@19.3.0-canary-b546603b-20260121))(react@19.3.0-canary-b546603b-20260121)(sass@1.77.8): dependencies: '@next/env': 16.0.8 '@swc/helpers': 0.5.15 caniuse-lite: 1.0.30001746 postcss: 8.4.31 - react: 19.3.0-canary-d2908752-20260119 - react-dom: 19.3.0-canary-d2908752-20260119(react@19.3.0-canary-d2908752-20260119) - styled-jsx: 5.1.6(@babel/core@7.26.10)(babel-plugin-macros@3.1.0)(react@19.3.0-canary-d2908752-20260119) + react: 19.3.0-canary-b546603b-20260121 + react-dom: 19.3.0-canary-b546603b-20260121(react@19.3.0-canary-b546603b-20260121) + styled-jsx: 5.1.6(@babel/core@7.26.10)(babel-plugin-macros@3.1.0)(react@19.3.0-canary-b546603b-20260121) optionalDependencies: '@next/swc-darwin-arm64': 16.0.8 '@next/swc-darwin-x64': 16.0.8 @@ -35373,31 +35373,31 @@ snapshots: dependencies: ansi-regex: 5.0.1 ansi-styles: 5.2.0 - react-is: 19.3.0-canary-d2908752-20260119 + react-is: 19.3.0-canary-b546603b-20260121 pretty-format@29.5.0: dependencies: '@jest/schemas': 29.4.3 ansi-styles: 5.2.0 - react-is: 19.3.0-canary-d2908752-20260119 + react-is: 19.3.0-canary-b546603b-20260121 pretty-format@29.7.0: dependencies: '@jest/schemas': 29.6.3 ansi-styles: 5.2.0 - react-is: 19.3.0-canary-d2908752-20260119 + react-is: 19.3.0-canary-b546603b-20260121 pretty-format@30.0.0-alpha.6: dependencies: '@jest/schemas': 30.0.0-alpha.6 ansi-styles: 5.2.0 - react-is: 19.3.0-canary-d2908752-20260119 + react-is: 19.3.0-canary-b546603b-20260121 pretty-format@30.2.0: dependencies: '@jest/schemas': 30.0.5 ansi-styles: 5.2.0 - react-is: 19.3.0-canary-d2908752-20260119 + react-is: 19.3.0-canary-b546603b-20260121 pretty-ms@7.0.0: dependencies: @@ -35461,7 +35461,7 @@ snapshots: dependencies: loose-envify: 1.4.0 object-assign: 4.1.1 - react-is: 19.3.0-canary-d2908752-20260119 + react-is: 19.3.0-canary-b546603b-20260121 property-information@5.6.0: dependencies: @@ -35673,31 +35673,31 @@ snapshots: transitivePeerDependencies: - supports-color - react-dom@0.0.0-experimental-d2908752-20260119(react@19.3.0-canary-d2908752-20260119): + react-dom@0.0.0-experimental-b546603b-20260121(react@19.3.0-canary-b546603b-20260121): dependencies: - react: 19.3.0-canary-d2908752-20260119 - scheduler: 0.28.0-canary-d2908752-20260119 + react: 19.3.0-canary-b546603b-20260121 + scheduler: 0.28.0-canary-b546603b-20260121 - react-dom@19.3.0-canary-d2908752-20260119(react@19.3.0-canary-d2908752-20260119): + react-dom@19.3.0-canary-b546603b-20260121(react@19.3.0-canary-b546603b-20260121): dependencies: - react: 19.3.0-canary-d2908752-20260119 - scheduler: 0.28.0-canary-d2908752-20260119 + react: 19.3.0-canary-b546603b-20260121 + scheduler: 0.28.0-canary-b546603b-20260121 react-dom@19.3.0-canary-fd524fe0-20251121(react@19.3.0-canary-fd524fe0-20251121): dependencies: react: 19.3.0-canary-fd524fe0-20251121 - scheduler: 0.28.0-canary-d2908752-20260119 + scheduler: 0.28.0-canary-b546603b-20260121 - react-is@19.3.0-canary-d2908752-20260119: {} + react-is@19.3.0-canary-b546603b-20260121: {} react-is@19.3.0-canary-fd524fe0-20251121: {} react-lifecycles-compat@3.0.4: {} - react-medium-image-zoom@5.3.0(react-dom@19.3.0-canary-d2908752-20260119(react@19.3.0-canary-d2908752-20260119))(react@19.3.0-canary-d2908752-20260119): + react-medium-image-zoom@5.3.0(react-dom@19.3.0-canary-b546603b-20260121(react@19.3.0-canary-b546603b-20260121))(react@19.3.0-canary-b546603b-20260121): dependencies: - react: 19.3.0-canary-d2908752-20260119 - react-dom: 19.3.0-canary-d2908752-20260119(react@19.3.0-canary-d2908752-20260119) + react: 19.3.0-canary-b546603b-20260121 + react-dom: 19.3.0-canary-b546603b-20260121(react@19.3.0-canary-b546603b-20260121) react-number-format@5.4.0(react-dom@19.3.0-canary-fd524fe0-20251121(react@19.3.0-canary-fd524fe0-20251121))(react@19.3.0-canary-fd524fe0-20251121): dependencies: @@ -35715,10 +35715,10 @@ snapshots: optionalDependencies: '@types/react': 19.2.2 - react-remove-scroll-bar@2.3.8(@types/react@19.2.2)(react@19.3.0-canary-d2908752-20260119): + react-remove-scroll-bar@2.3.8(@types/react@19.2.2)(react@19.3.0-canary-b546603b-20260121): dependencies: - react: 19.3.0-canary-d2908752-20260119 - react-style-singleton: 2.2.3(@types/react@19.2.2)(react@19.3.0-canary-d2908752-20260119) + react: 19.3.0-canary-b546603b-20260121 + react-style-singleton: 2.2.3(@types/react@19.2.2)(react@19.3.0-canary-b546603b-20260121) tslib: 2.8.1 optionalDependencies: '@types/react': 19.2.2 @@ -35734,59 +35734,59 @@ snapshots: optionalDependencies: '@types/react': 19.2.2 - react-remove-scroll@2.7.1(@types/react@19.2.2)(react@19.3.0-canary-d2908752-20260119): + react-remove-scroll@2.7.1(@types/react@19.2.2)(react@19.3.0-canary-b546603b-20260121): dependencies: - react: 19.3.0-canary-d2908752-20260119 - react-remove-scroll-bar: 2.3.8(@types/react@19.2.2)(react@19.3.0-canary-d2908752-20260119) - react-style-singleton: 2.2.3(@types/react@19.2.2)(react@19.3.0-canary-d2908752-20260119) + react: 19.3.0-canary-b546603b-20260121 + react-remove-scroll-bar: 2.3.8(@types/react@19.2.2)(react@19.3.0-canary-b546603b-20260121) + react-style-singleton: 2.2.3(@types/react@19.2.2)(react@19.3.0-canary-b546603b-20260121) tslib: 2.8.1 - use-callback-ref: 1.3.3(@types/react@19.2.2)(react@19.3.0-canary-d2908752-20260119) - use-sidecar: 1.1.3(@types/react@19.2.2)(react@19.3.0-canary-d2908752-20260119) + use-callback-ref: 1.3.3(@types/react@19.2.2)(react@19.3.0-canary-b546603b-20260121) + use-sidecar: 1.1.3(@types/react@19.2.2)(react@19.3.0-canary-b546603b-20260121) optionalDependencies: '@types/react': 19.2.2 - react-server-dom-turbopack@0.0.0-experimental-d2908752-20260119(react-dom@19.3.0-canary-d2908752-20260119(react@19.3.0-canary-d2908752-20260119))(react@19.3.0-canary-d2908752-20260119): + react-server-dom-turbopack@0.0.0-experimental-b546603b-20260121(react-dom@19.3.0-canary-b546603b-20260121(react@19.3.0-canary-b546603b-20260121))(react@19.3.0-canary-b546603b-20260121): dependencies: acorn-loose: 8.3.0 neo-async: 2.6.1 - react: 19.3.0-canary-d2908752-20260119 - react-dom: 19.3.0-canary-d2908752-20260119(react@19.3.0-canary-d2908752-20260119) + react: 19.3.0-canary-b546603b-20260121 + react-dom: 19.3.0-canary-b546603b-20260121(react@19.3.0-canary-b546603b-20260121) - react-server-dom-turbopack@19.3.0-canary-d2908752-20260119(react-dom@19.3.0-canary-d2908752-20260119(react@19.3.0-canary-d2908752-20260119))(react@19.3.0-canary-d2908752-20260119): + react-server-dom-turbopack@19.3.0-canary-b546603b-20260121(react-dom@19.3.0-canary-b546603b-20260121(react@19.3.0-canary-b546603b-20260121))(react@19.3.0-canary-b546603b-20260121): dependencies: acorn-loose: 8.3.0 neo-async: 2.6.1 - react: 19.3.0-canary-d2908752-20260119 - react-dom: 19.3.0-canary-d2908752-20260119(react@19.3.0-canary-d2908752-20260119) + react: 19.3.0-canary-b546603b-20260121 + react-dom: 19.3.0-canary-b546603b-20260121(react@19.3.0-canary-b546603b-20260121) - react-server-dom-webpack@0.0.0-experimental-d2908752-20260119(react-dom@19.3.0-canary-d2908752-20260119(react@19.3.0-canary-d2908752-20260119))(react@19.3.0-canary-d2908752-20260119)(webpack@5.98.0(@swc/core@1.11.24(@swc/helpers@0.5.15))): + react-server-dom-webpack@0.0.0-experimental-b546603b-20260121(react-dom@19.3.0-canary-b546603b-20260121(react@19.3.0-canary-b546603b-20260121))(react@19.3.0-canary-b546603b-20260121)(webpack@5.98.0(@swc/core@1.11.24(@swc/helpers@0.5.15))): dependencies: acorn-loose: 8.3.0 neo-async: 2.6.1 - react: 19.3.0-canary-d2908752-20260119 - react-dom: 19.3.0-canary-d2908752-20260119(react@19.3.0-canary-d2908752-20260119) + react: 19.3.0-canary-b546603b-20260121 + react-dom: 19.3.0-canary-b546603b-20260121(react@19.3.0-canary-b546603b-20260121) webpack: 5.98.0(@swc/core@1.11.24(@swc/helpers@0.5.15)) webpack-sources: 3.2.3(patch_hash=jbynf5dc46ambamq3wuyho6hkq) - react-server-dom-webpack@19.3.0-canary-d2908752-20260119(react-dom@19.3.0-canary-d2908752-20260119(react@19.3.0-canary-d2908752-20260119))(react@19.3.0-canary-d2908752-20260119)(webpack@5.98.0(@swc/core@1.11.24(@swc/helpers@0.5.15))): + react-server-dom-webpack@19.3.0-canary-b546603b-20260121(react-dom@19.3.0-canary-b546603b-20260121(react@19.3.0-canary-b546603b-20260121))(react@19.3.0-canary-b546603b-20260121)(webpack@5.98.0(@swc/core@1.11.24(@swc/helpers@0.5.15))): dependencies: acorn-loose: 8.3.0 neo-async: 2.6.1 - react: 19.3.0-canary-d2908752-20260119 - react-dom: 19.3.0-canary-d2908752-20260119(react@19.3.0-canary-d2908752-20260119) + react: 19.3.0-canary-b546603b-20260121 + react-dom: 19.3.0-canary-b546603b-20260121(react@19.3.0-canary-b546603b-20260121) webpack: 5.98.0(@swc/core@1.11.24(@swc/helpers@0.5.15)) webpack-sources: 3.2.3(patch_hash=jbynf5dc46ambamq3wuyho6hkq) - react-shallow-renderer@16.15.0(react@19.3.0-canary-d2908752-20260119): + react-shallow-renderer@16.15.0(react@19.3.0-canary-b546603b-20260121): dependencies: object-assign: 4.1.1 - react: 19.3.0-canary-d2908752-20260119 - react-is: 19.3.0-canary-d2908752-20260119 + react: 19.3.0-canary-b546603b-20260121 + react-is: 19.3.0-canary-b546603b-20260121 - react-ssr-prepass@1.0.8(react-is@19.3.0-canary-fd524fe0-20251121)(react@19.3.0-canary-d2908752-20260119): + react-ssr-prepass@1.0.8(react-is@19.3.0-canary-fd524fe0-20251121)(react@19.3.0-canary-b546603b-20260121): dependencies: object-is: 1.0.2 - react: 19.3.0-canary-d2908752-20260119 + react: 19.3.0-canary-b546603b-20260121 react-is: 19.3.0-canary-fd524fe0-20251121 react-style-singleton@2.2.1(@types/react@19.2.2)(react@19.3.0-canary-fd524fe0-20251121): @@ -35798,10 +35798,10 @@ snapshots: optionalDependencies: '@types/react': 19.2.2 - react-style-singleton@2.2.3(@types/react@19.2.2)(react@19.3.0-canary-d2908752-20260119): + react-style-singleton@2.2.3(@types/react@19.2.2)(react@19.3.0-canary-b546603b-20260121): dependencies: get-nonce: 1.0.1 - react: 19.3.0-canary-d2908752-20260119 + react: 19.3.0-canary-b546603b-20260121 tslib: 2.8.1 optionalDependencies: '@types/react': 19.2.2 @@ -35814,12 +35814,12 @@ snapshots: optionalDependencies: '@types/react': 19.2.2 - react-test-renderer@18.2.0(react@19.3.0-canary-d2908752-20260119): + react-test-renderer@18.2.0(react@19.3.0-canary-b546603b-20260121): dependencies: - react: 19.3.0-canary-d2908752-20260119 - react-is: 19.3.0-canary-d2908752-20260119 - react-shallow-renderer: 16.15.0(react@19.3.0-canary-d2908752-20260119) - scheduler: 0.28.0-canary-d2908752-20260119 + react: 19.3.0-canary-b546603b-20260121 + react-is: 19.3.0-canary-b546603b-20260121 + react-shallow-renderer: 16.15.0(react@19.3.0-canary-b546603b-20260121) + scheduler: 0.28.0-canary-b546603b-20260121 react-textarea-autosize@8.5.3(@types/react@19.2.2)(react@19.3.0-canary-fd524fe0-20251121): dependencies: @@ -35830,20 +35830,20 @@ snapshots: transitivePeerDependencies: - '@types/react' - react-virtualized@9.22.3(react-dom@19.3.0-canary-d2908752-20260119(react@19.3.0-canary-d2908752-20260119))(react@19.3.0-canary-d2908752-20260119): + react-virtualized@9.22.3(react-dom@19.3.0-canary-b546603b-20260121(react@19.3.0-canary-b546603b-20260121))(react@19.3.0-canary-b546603b-20260121): dependencies: '@babel/runtime': 7.27.0 clsx: 1.1.1 dom-helpers: 5.2.1 loose-envify: 1.4.0 prop-types: 15.8.1 - react: 19.3.0-canary-d2908752-20260119 - react-dom: 19.3.0-canary-d2908752-20260119(react@19.3.0-canary-d2908752-20260119) + react: 19.3.0-canary-b546603b-20260121 + react-dom: 19.3.0-canary-b546603b-20260121(react@19.3.0-canary-b546603b-20260121) react-lifecycles-compat: 3.0.4 - react@0.0.0-experimental-d2908752-20260119: {} + react@0.0.0-experimental-b546603b-20260121: {} - react@19.3.0-canary-d2908752-20260119: {} + react@19.3.0-canary-b546603b-20260121: {} react@19.3.0-canary-fd524fe0-20251121: {} @@ -36671,9 +36671,9 @@ snapshots: dependencies: xmlchars: 2.2.0 - scheduler@0.0.0-experimental-d2908752-20260119: {} + scheduler@0.0.0-experimental-b546603b-20260121: {} - scheduler@0.28.0-canary-d2908752-20260119: {} + scheduler@0.28.0-canary-b546603b-20260121: {} schema-utils@2.7.1: dependencies: @@ -37566,10 +37566,10 @@ snapshots: postcss: 7.0.32 postcss-load-plugins: 2.3.0 - styled-jsx@5.1.6(@babel/core@7.26.10)(babel-plugin-macros@3.1.0)(react@19.3.0-canary-d2908752-20260119): + styled-jsx@5.1.6(@babel/core@7.26.10)(babel-plugin-macros@3.1.0)(react@19.3.0-canary-b546603b-20260121): dependencies: client-only: 0.0.1 - react: 19.3.0-canary-d2908752-20260119 + react: 19.3.0-canary-b546603b-20260121 optionalDependencies: '@babel/core': 7.26.10 babel-plugin-macros: 3.1.0 @@ -37673,11 +37673,11 @@ snapshots: '@swc/counter': 0.1.3 webpack: 5.98.0(@swc/core@1.11.24(@swc/helpers@0.5.15))(esbuild@0.25.9) - swr@2.2.4(react@19.3.0-canary-d2908752-20260119): + swr@2.2.4(react@19.3.0-canary-b546603b-20260121): dependencies: client-only: 0.0.1 - react: 19.3.0-canary-d2908752-20260119 - use-sync-external-store: 1.5.0(react@19.3.0-canary-d2908752-20260119) + react: 19.3.0-canary-b546603b-20260121 + use-sync-external-store: 1.5.0(react@19.3.0-canary-b546603b-20260121) symbol-observable@1.0.1: {} @@ -38533,9 +38533,9 @@ snapshots: unist-util-is: 6.0.0 unist-util-visit-parents: 6.0.1 - unistore@3.4.1(react@19.3.0-canary-d2908752-20260119): + unistore@3.4.1(react@19.3.0-canary-b546603b-20260121): optionalDependencies: - react: 19.3.0-canary-d2908752-20260119 + react: 19.3.0-canary-b546603b-20260121 universal-github-app-jwt@1.1.1: dependencies: @@ -38670,9 +38670,9 @@ snapshots: optionalDependencies: '@types/react': 19.2.2 - use-callback-ref@1.3.3(@types/react@19.2.2)(react@19.3.0-canary-d2908752-20260119): + use-callback-ref@1.3.3(@types/react@19.2.2)(react@19.3.0-canary-b546603b-20260121): dependencies: - react: 19.3.0-canary-d2908752-20260119 + react: 19.3.0-canary-b546603b-20260121 tslib: 2.8.1 optionalDependencies: '@types/react': 19.2.2 @@ -38702,17 +38702,17 @@ snapshots: optionalDependencies: '@types/react': 19.2.2 - use-sidecar@1.1.3(@types/react@19.2.2)(react@19.3.0-canary-d2908752-20260119): + use-sidecar@1.1.3(@types/react@19.2.2)(react@19.3.0-canary-b546603b-20260121): dependencies: detect-node-es: 1.1.0 - react: 19.3.0-canary-d2908752-20260119 + react: 19.3.0-canary-b546603b-20260121 tslib: 2.8.1 optionalDependencies: '@types/react': 19.2.2 - use-sync-external-store@1.5.0(react@19.3.0-canary-d2908752-20260119): + use-sync-external-store@1.5.0(react@19.3.0-canary-b546603b-20260121): dependencies: - react: 19.3.0-canary-d2908752-20260119 + react: 19.3.0-canary-b546603b-20260121 util-deprecate@1.0.2: {} diff --git a/turbopack/crates/turbo-bincode/src/lib.rs b/turbopack/crates/turbo-bincode/src/lib.rs index a70a3a71f02d0b..f44eee82a3b008 100644 --- a/turbopack/crates/turbo-bincode/src/lib.rs +++ b/turbopack/crates/turbo-bincode/src/lib.rs @@ -21,11 +21,11 @@ pub type TurboBincodeDecoder<'a> = pub type AnyEncodeFn = fn(&dyn Any, &mut TurboBincodeEncoder<'_>) -> Result<(), EncodeError>; pub type AnyDecodeFn = fn(&mut TurboBincodeDecoder<'_>) -> Result; -fn new_turbo_bincode_encoder(buf: &mut TurboBincodeBuffer) -> TurboBincodeEncoder<'_> { +pub fn new_turbo_bincode_encoder(buf: &mut TurboBincodeBuffer) -> TurboBincodeEncoder<'_> { EncoderImpl::new(TurboBincodeWriter::new(buf), TURBO_BINCODE_CONFIG) } -fn new_turbo_bincode_decoder(buffer: &[u8]) -> TurboBincodeDecoder<'_> { +pub fn new_turbo_bincode_decoder(buffer: &[u8]) -> TurboBincodeDecoder<'_> { DecoderImpl::new(TurboBincodeReader::new(buffer), TURBO_BINCODE_CONFIG, ()) } diff --git a/turbopack/crates/turbo-tasks-backend/src/backend/counter_map.rs b/turbopack/crates/turbo-tasks-backend/src/backend/counter_map.rs index 28f748a651f7de..4dd4444f955c5f 100644 --- a/turbopack/crates/turbo-tasks-backend/src/backend/counter_map.rs +++ b/turbopack/crates/turbo-tasks-backend/src/backend/counter_map.rs @@ -1,6 +1,3 @@ -// TODO(PR 2): Remove this once the storage schema is integrated with the rest of the codebase. -// This module is scaffolding for the TaskStorage macro and is not yet used. -#![allow(dead_code)] use std::{ hash::{BuildHasherDefault, Hash}, ops::{Add, AddAssign, Sub}, @@ -84,7 +81,7 @@ impl CounterValue for i32 { } impl CounterMap { - fn new() -> Self { + pub fn new() -> Self { Self(AutoMap::default()) } @@ -92,6 +89,13 @@ impl CounterMap { self.0.is_empty() } + pub fn shrink_to_fit(&mut self) + where + K: Eq + Hash, + { + self.0.shrink_to_fit(); + } + pub fn len(&self) -> usize { self.0.len() } @@ -102,7 +106,15 @@ impl CounterMap { { self.0.get(key) } - + // TODO(lukesandberg): this is just here for the CachedDataItem adaptor layer, can be removed + // once that is gone. + #[doc(hidden)] + pub fn get_mut(&mut self, _key: &K) -> Option<&mut V> + where + K: Eq + Hash, + { + unreachable!("This should never be called, please insert instead") + } pub fn iter(&self) -> impl Iterator { self.0.iter() } @@ -117,7 +129,6 @@ impl CounterMap { impl CounterMap { /// Insert a key-value pair. Panics if value is zero (invariant: zero values are not stored). - #[cfg(test)] pub fn insert(&mut self, key: K, value: V) -> Option { debug_assert!( !value.is_zero(), diff --git a/turbopack/crates/turbo-tasks-backend/src/backend/dynamic_storage.rs b/turbopack/crates/turbo-tasks-backend/src/backend/dynamic_storage.rs deleted file mode 100644 index 19aa63156477be..00000000000000 --- a/turbopack/crates/turbo-tasks-backend/src/backend/dynamic_storage.rs +++ /dev/null @@ -1,194 +0,0 @@ -use either::Either; -use turbo_tasks::KeyValuePair; - -use crate::data::{ - CachedDataItem, CachedDataItemKey, CachedDataItemStorage, CachedDataItemType, - CachedDataItemValue, CachedDataItemValueRef, CachedDataItemValueRefMut, -}; - -#[derive(Debug, Clone)] -pub struct DynamicStorage { - map: Vec, -} - -impl DynamicStorage { - pub fn new() -> Self { - Self { - map: Default::default(), - } - } - - fn get_or_create_map_mut(&mut self, ty: CachedDataItemType) -> &mut CachedDataItemStorage { - let i = self.map.iter().position(|m| m.ty() == ty); - if let Some(i) = i { - &mut self.map[i] - } else { - self.map.reserve_exact(1); - self.map.push(CachedDataItemStorage::new(ty)); - self.map.last_mut().unwrap() - } - } - - fn get_map_mut(&mut self, ty: CachedDataItemType) -> Option<&mut CachedDataItemStorage> { - self.map.iter_mut().find(|m| m.ty() == ty) - } - - fn get_map_index(&mut self, ty: CachedDataItemType) -> Option { - self.map.iter_mut().position(|m| m.ty() == ty) - } - - fn get_or_create_map_index(&mut self, ty: CachedDataItemType) -> usize { - let i = self.map.iter().position(|m| m.ty() == ty); - if let Some(i) = i { - i - } else { - let i = self.map.len(); - self.map.reserve_exact(1); - self.map.push(CachedDataItemStorage::new(ty)); - i - } - } - - fn get_map(&self, ty: CachedDataItemType) -> Option<&CachedDataItemStorage> { - self.map.iter().find(|m| m.ty() == ty) - } - - pub fn add(&mut self, item: CachedDataItem) -> bool { - let ty = item.ty(); - self.get_or_create_map_mut(ty).add(item) - } - - pub fn extend( - &mut self, - ty: CachedDataItemType, - iterator: impl Iterator, - ) -> bool { - self.get_or_create_map_mut(ty).extend(iterator) - } - - pub fn insert(&mut self, item: CachedDataItem) -> Option { - let ty = item.ty(); - self.get_or_create_map_mut(ty).insert(item) - } - - pub fn remove(&mut self, key: &CachedDataItemKey) -> Option { - self.get_map_index(key.ty()).and_then(|i| { - let storage = &mut self.map[i]; - let result = storage.remove(key); - if result.is_some() && storage.is_empty() { - self.map.swap_remove(i); - self.map.shrink_to_fit(); - } - result - }) - } - - pub fn get(&self, key: &CachedDataItemKey) -> Option> { - self.get_map(key.ty()).and_then(|m| m.get(key)) - } - - pub fn get_mut(&mut self, key: &CachedDataItemKey) -> Option> { - self.get_map_mut(key.ty()).and_then(|m| m.get_mut(key)) - } - - pub fn get_mut_or_insert_with( - &mut self, - key: CachedDataItemKey, - f: impl FnOnce() -> CachedDataItemValue, - ) -> CachedDataItemValueRefMut<'_> { - self.get_or_create_map_mut(key.ty()) - .get_mut_or_insert_with(key, f) - } - - pub fn contains_key(&self, key: &CachedDataItemKey) -> bool { - self.get_map(key.ty()) - .map(|m| m.contains_key(key)) - .unwrap_or_default() - } - - pub fn count(&self, ty: CachedDataItemType) -> usize { - self.get_map(ty).map(|m| m.len()).unwrap_or_default() - } - - pub fn iter( - &self, - ty: CachedDataItemType, - ) -> impl Iterator)> { - self.get_map(ty).map(|m| m.iter()).into_iter().flatten() - } - - pub fn iter_all( - &self, - ) -> impl Iterator)> { - self.map.iter().flat_map(|m| m.iter()) - } - - pub fn extract_if<'l, F>( - &'l mut self, - ty: CachedDataItemType, - mut f: F, - ) -> impl Iterator + use<'l, F> - where - F: for<'a> FnMut(CachedDataItemKey, CachedDataItemValueRef<'a>) -> bool + 'l, - { - // TODO this could be more efficient when the storage would support extract_if directly. - // This requires some macro magic to make it work... - // But we could potentially avoid the two temporary Vecs. - let Some(i) = self.get_map_index(ty) else { - return Either::Left(std::iter::empty()); - }; - let storage = &mut self.map[i]; - let items_to_extract = storage - .iter() - .filter(|(k, v)| f(*k, *v)) - .map(|(key, _)| key) - .collect::>(); - let items = items_to_extract - .into_iter() - .map(move |key| { - let value = storage.remove(&key).unwrap(); - CachedDataItem::from_key_and_value(key, value) - }) - .collect::>(); - if self.map[i].is_empty() { - self.map.swap_remove(i); - self.map.shrink_to_fit(); - } - Either::Right(items.into_iter()) - } - - pub fn update( - &mut self, - key: CachedDataItemKey, - update: impl FnOnce(Option) -> Option, - ) { - let i = self.get_or_create_map_index(key.ty()); - let map = &mut self.map[i]; - map.update(key, update); - if map.is_empty() { - self.map.swap_remove(i); - self.map.shrink_to_fit(); - } - } - - pub fn len(&self) -> usize { - self.map.iter().map(|m| m.len()).sum() - } - - pub fn shrink_to_fit(&mut self, ty: CachedDataItemType) { - if let Some(map) = self.get_map_mut(ty) { - map.shrink_to_fit(); - } - } - - pub fn snapshot_for_persisting(&self) -> Self { - Self { - map: self - .map - .iter() - .filter(|m| m.ty().is_persistent()) - .cloned() - .collect(), - } - } -} diff --git a/turbopack/crates/turbo-tasks-backend/src/backend/mod.rs b/turbopack/crates/turbo-tasks-backend/src/backend/mod.rs index d018ec6e0103ba..6e1bba6de53b88 100644 --- a/turbopack/crates/turbo-tasks-backend/src/backend/mod.rs +++ b/turbopack/crates/turbo-tasks-backend/src/backend/mod.rs @@ -1,8 +1,7 @@ mod counter_map; -mod dynamic_storage; mod operation; mod storage; -mod storage_schema; +pub mod storage_schema; use std::{ borrow::Cow, @@ -26,7 +25,7 @@ use smallvec::{SmallVec, smallvec}; use tokio::time::{Duration, Instant}; use tracing::{Span, trace_span}; use turbo_tasks::{ - CellId, FxDashMap, KeyValuePair, RawVc, ReadCellOptions, ReadCellTracking, ReadConsistency, + CellId, FxDashMap, RawVc, ReadCellOptions, ReadCellTracking, ReadConsistency, ReadOutputOptions, ReadTracking, TRANSIENT_TASK_BIT, TaskExecutionReason, TaskId, TaskPriority, TraitTypeId, TurboTasksBackendApi, ValueTypeId, backend::{ @@ -43,7 +42,10 @@ use turbo_tasks::{ util::{IdFactoryWithReuse, good_chunk_size, into_chunks}, }; -pub use self::{operation::AnyOperation, storage::TaskDataCategory}; +pub use self::{ + operation::AnyOperation, + storage::{SpecificTaskDataCategory, TaskDataCategory}, +}; #[cfg(feature = "trace_task_dirty")] use crate::backend::operation::TaskDirtyCause; use crate::{ @@ -56,9 +58,9 @@ use crate::{ make_task_dirty_internal, prepare_new_children, }, storage::{ - InnerStorageSnapshot, Storage, count, get, get_many, get_mut, get_mut_or_insert_with, - iter_many, remove, + Storage, count, get, get_many, get_mut, get_mut_or_insert_with, iter_many, remove, }, + storage_schema::{TaskStorage, TaskStorageAccessors}, }, backing_storage::BackingStorage, data::{ @@ -1066,75 +1068,54 @@ impl TurboTasksBackendInner { let snapshot_time = Instant::now(); drop(snapshot_request); - let preprocess = |task_id: TaskId, inner: &storage::InnerStorage| { + let preprocess = |task_id: TaskId, inner: &TaskStorage| { if task_id.is_transient() { return (None, None); } - let len = inner.len(); - let meta_restored = inner.state().meta_restored(); - let data_restored = inner.state().data_restored(); + let meta_restored = inner.flags.meta_restored(); + let data_restored = inner.flags.data_restored(); - let mut meta = meta_restored.then(|| Vec::with_capacity(len)); - let mut data = data_restored.then(|| Vec::with_capacity(len)); - for (key, value) in inner.iter_all() { - if key.is_persistent() && value.is_persistent() { - match key.category() { - TaskDataCategory::Meta => { - if let Some(meta) = &mut meta { - meta.push(CachedDataItem::from_key_and_value_ref(key, value)) - } - } - TaskDataCategory::Data => { - if let Some(data) = &mut data { - data.push(CachedDataItem::from_key_and_value_ref(key, value)) - } - } - _ => {} - } - } - } + // Encode meta/data directly from TaskStorage + let meta = meta_restored.then(|| inner.clone_meta_snapshot()); + let data = data_restored.then(|| inner.clone_data_snapshot()); (meta, data) }; - let process = |task_id: TaskId, (meta, data): (Option>, Option>)| { - // TODO: perf: Instead of returning a `Vec` of individually allocated `SmallVec`s, it'd - // be better to append everything to a flat per-task or per-shard `Vec`, and have - // each `serialize` call return `(start_idx, end_idx)`. - ( - task_id, - meta.map(|d| self.backing_storage.serialize(task_id, &d)), - data.map(|d| self.backing_storage.serialize(task_id, &d)), - ) - }; - let process_snapshot = |task_id: TaskId, inner: Box| { + let process = + |task_id: TaskId, (meta, data): (Option, Option)| { + // TODO: perf: Instead of returning a `Vec` of individually allocated `SmallVec`s, + // it'd be better to append everything to a flat per-task or + // per-shard `Vec`, and have each `serialize` call return + // `(start_idx, end_idx)`. + ( + task_id, + meta.map(|d| { + self.backing_storage + .serialize(task_id, &d, SpecificTaskDataCategory::Meta) + }), + data.map(|d| { + self.backing_storage + .serialize(task_id, &d, SpecificTaskDataCategory::Data) + }), + ) + }; + let process_snapshot = |task_id: TaskId, inner: Box| { if task_id.is_transient() { return (task_id, None, None); } - let len = inner.len(); - let mut meta = inner.meta_modified.then(|| Vec::with_capacity(len)); - let mut data = inner.data_modified.then(|| Vec::with_capacity(len)); - for (key, value) in inner.iter_all() { - if key.is_persistent() && value.is_persistent() { - match key.category() { - TaskDataCategory::Meta => { - if let Some(meta) = &mut meta { - meta.push(CachedDataItem::from_key_and_value_ref(key, value)); - } - } - TaskDataCategory::Data => { - if let Some(data) = &mut data { - data.push(CachedDataItem::from_key_and_value_ref(key, value)); - } - } - _ => {} - } - } - } + + // Encode meta/data directly from TaskStorage snapshot ( task_id, - meta.map(|meta| self.backing_storage.serialize(task_id, &meta)), - data.map(|data| self.backing_storage.serialize(task_id, &data)), + inner.flags.meta_modified().then(|| { + self.backing_storage + .serialize(task_id, &inner, SpecificTaskDataCategory::Meta) + }), + inner.flags.data_modified().then(|| { + self.backing_storage + .serialize(task_id, &inner, SpecificTaskDataCategory::Data) + }), ) }; @@ -2599,17 +2580,20 @@ impl TurboTasksBackendInner { } } - // Shrink memory usage - task.shrink_to_fit(CachedDataItemType::CellData); - task.shrink_to_fit(CachedDataItemType::TransientCellData); - task.shrink_to_fit(CachedDataItemType::CellTypeMaxIndex); - task.shrink_to_fit(CachedDataItemType::CellDependency); - task.shrink_to_fit(CachedDataItemType::OutputDependency); - task.shrink_to_fit(CachedDataItemType::CollectiblesDependency); - task.shrink_to_fit(CachedDataItemType::OutdatedOutputDependency); - task.shrink_to_fit(CachedDataItemType::OutdatedCellDependency); - task.shrink_to_fit(CachedDataItemType::OutdatedCollectiblesDependency); - task.shrink_to_fit(CachedDataItemType::OutdatedCollectible); + // Shrink memory usage for collections that are only mutated during/after execution + task.shrink_cell_data(); + task.shrink_transient_cell_data(); + task.shrink_cell_type_max_index(); + task.shrink_cell_dependencies(); + task.shrink_output_dependencies(); + task.shrink_collectibles_dependencies(); + task.shrink_outdated_cell_dependencies(); + task.shrink_outdated_output_dependencies(); + task.shrink_outdated_collectibles(); + task.shrink_outdated_collectibles_dependencies(); + task.shrink_children(); + task.shrink_collectibles(); + task.shrink_in_progress_cells(); drop(task); } diff --git a/turbopack/crates/turbo-tasks-backend/src/backend/operation/aggregation_update.rs b/turbopack/crates/turbo-tasks-backend/src/backend/operation/aggregation_update.rs index 57a95445cd4938..4c229917273308 100644 --- a/turbopack/crates/turbo-tasks-backend/src/backend/operation/aggregation_update.rs +++ b/turbopack/crates/turbo-tasks-backend/src/backend/operation/aggregation_update.rs @@ -33,6 +33,7 @@ use crate::{ storage::{ count, get, get_many, iter_many, remove, update, update_count, update_count_and_get, }, + storage_schema::TaskStorageAccessors, }, data::{ ActivenessState, AggregationNumber, CachedDataItem, CachedDataItemKey, CachedDataItemType, diff --git a/turbopack/crates/turbo-tasks-backend/src/backend/operation/cleanup_old_edges.rs b/turbopack/crates/turbo-tasks-backend/src/backend/operation/cleanup_old_edges.rs index c2413481667844..8d27912df4f336 100644 --- a/turbopack/crates/turbo-tasks-backend/src/backend/operation/cleanup_old_edges.rs +++ b/turbopack/crates/turbo-tasks-backend/src/backend/operation/cleanup_old_edges.rs @@ -9,13 +9,14 @@ use crate::{ backend::{ TaskDataCategory, get, get_many, operation::{ - AggregatedDataUpdate, ExecuteContext, Operation, TaskGuard, + AggregatedDataUpdate, ExecuteContext, Operation, aggregation_update::{ AggregationUpdateJob, AggregationUpdateQueue, InnerOfUppersLostFollowersJob, get_aggregation_number, get_uppers, is_aggregating_node, }, }, storage::update_count, + storage_schema::TaskStorageAccessors, }, data::{CachedDataItemKey, CellRef, CollectibleRef, CollectiblesRef}, }; diff --git a/turbopack/crates/turbo-tasks-backend/src/backend/operation/connect_child.rs b/turbopack/crates/turbo-tasks-backend/src/backend/operation/connect_child.rs index 9492f6bdce8255..3e14326df6a4cd 100644 --- a/turbopack/crates/turbo-tasks-backend/src/backend/operation/connect_child.rs +++ b/turbopack/crates/turbo-tasks-backend/src/backend/operation/connect_child.rs @@ -5,9 +5,10 @@ use crate::{ backend::{ TaskDataCategory, get_mut, operation::{ - ExecuteContext, Operation, TaskGuard, + ExecuteContext, Operation, aggregation_update::{AggregationUpdateJob, AggregationUpdateQueue}, }, + storage_schema::TaskStorageAccessors, }, data::{CachedDataItem, CachedDataItemKey, InProgressState, InProgressStateInner}, }; @@ -26,7 +27,7 @@ impl ConnectChildOperation { pub fn run( parent_task_id: Option, child_task_id: TaskId, - mut ctx: impl ExecuteContext, + mut ctx: impl ExecuteContext<'_>, ) { if let Some(parent_task_id) = parent_task_id { let mut parent_task = ctx.task(parent_task_id, TaskDataCategory::All); diff --git a/turbopack/crates/turbo-tasks-backend/src/backend/operation/leaf_distance_update.rs b/turbopack/crates/turbo-tasks-backend/src/backend/operation/leaf_distance_update.rs index 9fec97b41a6198..9fbd0b622b2eb8 100644 --- a/turbopack/crates/turbo-tasks-backend/src/backend/operation/leaf_distance_update.rs +++ b/turbopack/crates/turbo-tasks-backend/src/backend/operation/leaf_distance_update.rs @@ -12,8 +12,9 @@ use turbo_tasks::TaskId; use crate::{ backend::{ TaskDataCategory, - operation::{ExecuteContext, Operation, TaskGuard}, + operation::{ExecuteContext, Operation}, storage::{get, iter_many}, + storage_schema::TaskStorageAccessors, }, data::CachedDataItem, }; @@ -184,7 +185,7 @@ impl LeafDistanceUpdateQueue { } impl Operation for LeafDistanceUpdateQueue { - fn execute(mut self, ctx: &mut impl ExecuteContext) { + fn execute(mut self, ctx: &mut impl ExecuteContext<'_>) { if self.is_empty() { return; } diff --git a/turbopack/crates/turbo-tasks-backend/src/backend/operation/mod.rs b/turbopack/crates/turbo-tasks-backend/src/backend/operation/mod.rs index 0a50e8f33e340b..979f526f90b750 100644 --- a/turbopack/crates/turbo-tasks-backend/src/backend/operation/mod.rs +++ b/turbopack/crates/turbo-tasks-backend/src/backend/operation/mod.rs @@ -16,26 +16,23 @@ use std::{ use bincode::{Decode, Encode}; use turbo_tasks::{ - CellId, FxIndexMap, KeyValuePair, TaskId, TaskPriority, TurboTasksBackendApi, - TypedSharedReference, + CellId, FxIndexMap, TaskId, TaskPriority, TurboTasksBackendApi, TypedSharedReference, }; use crate::{ backend::{ OperationGuard, TaskDataCategory, TransientTask, TurboTasksBackend, TurboTasksBackendInner, storage::{SpecificTaskDataCategory, StorageWriteGuard, get, iter_many, remove}, + storage_schema::{TaskStorage, TaskStorageAccessors}, }, backing_storage::{BackingStorage, BackingStorageSealed}, - data::{ - CachedDataItem, CachedDataItemKey, CachedDataItemType, CachedDataItemValue, - CachedDataItemValueRef, CachedDataItemValueRefMut, Dirtyness, - }, + data::{CachedDataItemKey, Dirtyness}, }; pub trait Operation: Encode + Decode<()> + Default + TryFrom + Into { - fn execute(self, ctx: &mut impl ExecuteContext); + fn execute(self, ctx: &mut impl ExecuteContext<'_>); } #[derive(Copy, Clone)] @@ -162,21 +159,23 @@ where fn restore_task_data( &mut self, task_id: TaskId, - category: TaskDataCategory, - ) -> Vec { + category: SpecificTaskDataCategory, + ) -> TaskStorage { if !self.ensure_transaction() { - // If we don't need to restore, we can just return an empty vector - return Vec::new(); + // If we don't need to restore, we can just return an empty storage + return TaskStorage::default(); } let tx = self.get_tx(); + let mut storage = TaskStorage::default(); // Safety: `tx` is a valid transaction from `self.backend.backing_storage`. let result = unsafe { self.backend .backing_storage - .lookup_data(tx, task_id, category) + .lookup_data(tx, task_id, category, &mut storage) }; + match result { - Ok(data) => data, + Ok(()) => storage, Err(e) => { let task_name = self.backend.get_task_description(task_id); panic!( @@ -190,9 +189,12 @@ where fn restore_task_data_batch( &mut self, task_ids: &[TaskId], - category: TaskDataCategory, - ) -> Option>> { - debug_assert!(task_ids.len() > 1, "Use restore_task_data for single task"); + category: SpecificTaskDataCategory, + ) -> Option> { + debug_assert!( + task_ids.len() > 1, + "Use restore_task_data_typed for single task" + ); if !self.ensure_transaction() { // If we don't need to restore, we return None return None; @@ -248,8 +250,8 @@ where let mut task = self.backend.storage.access_mut(id); // TODO add is_restoring and avoid concurrent restores and duplicates tasks // ids in `task_ids` - if !task.state().is_restored(category) { - task.state_mut().set_restored(TaskDataCategory::All); + if !task.flags.is_restored(category) { + task.flags.set_restored(TaskDataCategory::All); } prepared_task_callback(self, id, category, task); } @@ -284,14 +286,14 @@ where let task = self.backend.storage.access_mut(task_id); let mut ready = true; if matches!(category, TaskDataCategory::Data | TaskDataCategory::All) - && !task.state().is_restored(TaskDataCategory::Data) + && !task.flags.is_restored(TaskDataCategory::Data) { tasks_to_restore_for_data.push(task_id); tasks_to_restore_for_data_indicies.push(i); ready = false; } if matches!(category, TaskDataCategory::Meta | TaskDataCategory::All) - && !task.state().is_restored(TaskDataCategory::Meta) + && !task.flags.is_restored(TaskDataCategory::Meta) { tasks_to_restore_for_meta.push(task_id); tasks_to_restore_for_meta_indicies.push(i); @@ -311,22 +313,23 @@ where 0 => {} 1 => { let task_id = tasks_to_restore_for_data[0]; - let data = self.restore_task_data(task_id, TaskDataCategory::Data); + let data = self.restore_task_data(task_id, SpecificTaskDataCategory::Data); let idx = tasks_to_restore_for_data_indicies[0]; tasks[idx].2 = Some(data); } _ => { - if let Some(data) = - self.restore_task_data_batch(&tasks_to_restore_for_data, TaskDataCategory::Data) - { + if let Some(data) = self.restore_task_data_batch( + &tasks_to_restore_for_data, + SpecificTaskDataCategory::Data, + ) { data.into_iter() .zip(tasks_to_restore_for_data_indicies) - .for_each(|(items, idx)| { - tasks[idx].2 = Some(items); + .for_each(|(item, idx)| { + tasks[idx].2 = Some(item); }); } else { for idx in tasks_to_restore_for_data_indicies { - tasks[idx].2 = Some(Vec::new()); + tasks[idx].2 = Some(TaskStorage::default()); } } } @@ -335,29 +338,30 @@ where 0 => {} 1 => { let task_id = tasks_to_restore_for_meta[0]; - let data = self.restore_task_data(task_id, TaskDataCategory::Meta); + let data = self.restore_task_data(task_id, SpecificTaskDataCategory::Meta); let idx = tasks_to_restore_for_meta_indicies[0]; tasks[idx].3 = Some(data); } _ => { - if let Some(data) = - self.restore_task_data_batch(&tasks_to_restore_for_meta, TaskDataCategory::Meta) - { + if let Some(data) = self.restore_task_data_batch( + &tasks_to_restore_for_meta, + SpecificTaskDataCategory::Meta, + ) { data.into_iter() .zip(tasks_to_restore_for_meta_indicies) - .for_each(|(items, idx)| { - tasks[idx].3 = Some(items); + .for_each(|(item, idx)| { + tasks[idx].3 = Some(item); }); } else { for idx in tasks_to_restore_for_meta_indicies { - tasks[idx].3 = Some(Vec::new()); + tasks[idx].3 = Some(TaskStorage::default()); } } } } - for (task_id, category, items_for_data, items_for_meta) in tasks { - if items_for_data.is_none() && items_for_meta.is_none() { + for (task_id, category, storage_for_data, storage_for_meta) in tasks { + if storage_for_data.is_none() && storage_for_meta.is_none() { continue; } #[cfg(debug_assertions)] @@ -369,23 +373,17 @@ where } let mut task = self.backend.storage.access_mut(task_id); - if let Some(items) = items_for_data - && !task.state().is_restored(TaskDataCategory::Data) + if let Some(storage) = storage_for_data + && !task.flags.is_restored(TaskDataCategory::Data) { - // TODO store items groups by type to be able to use extend here - for item in items { - task.add(item); - } - task.state_mut().set_restored(TaskDataCategory::Data); + task.restore_from(storage, TaskDataCategory::Data); + task.flags.set_restored(TaskDataCategory::Data); } - if let Some(items) = items_for_meta - && !task.state().is_restored(TaskDataCategory::Meta) + if let Some(storage) = storage_for_meta + && !task.flags.is_restored(TaskDataCategory::Meta) { - // TODO store items groups by type to be able to use extend here - for item in items { - task.add(item); - } - task.state_mut().set_restored(TaskDataCategory::Meta); + task.restore_from(storage, TaskDataCategory::Meta); + task.flags.set_restored(TaskDataCategory::Meta); } prepared_task_callback(self, task_id, category, task); #[cfg(debug_assertions)] @@ -420,23 +418,40 @@ where } let mut task = self.backend.storage.access_mut(task_id); - if !task.state().is_restored(category) { + if !task.flags.is_restored(category) { if task_id.is_transient() { - task.state_mut().set_restored(TaskDataCategory::All); + task.flags.set_restored(TaskDataCategory::All); } else { - for category in category { - if !task.state().is_restored(category) { - // Avoid holding the lock too long since this can also affect other tasks - drop(task); - - let items = self.restore_task_data(task_id, category); - task = self.backend.storage.access_mut(task_id); - if !task.state().is_restored(category) { - for item in items { - task.add(item); - } - task.state_mut().set_restored(category); - } + // Collect which categories need restoring while we have the lock + let needs_data = + category.includes_data() && !task.flags.is_restored(TaskDataCategory::Data); + let needs_meta = + category.includes_meta() && !task.flags.is_restored(TaskDataCategory::Meta); + + if needs_data || needs_meta { + // Avoid holding the lock too long since this can also affect other tasks + // Drop lock once, do all I/O, then re-acquire once + drop(task); + + let storage_data = needs_data + .then(|| self.restore_task_data(task_id, SpecificTaskDataCategory::Data)); + let storage_meta = needs_meta + .then(|| self.restore_task_data(task_id, SpecificTaskDataCategory::Meta)); + + task = self.backend.storage.access_mut(task_id); + + // Handle race conditions and merge + if let Some(storage) = storage_data + && !task.flags.is_restored(TaskDataCategory::Data) + { + task.restore_from(storage, TaskDataCategory::Data); + task.flags.set_restored(TaskDataCategory::Data); + } + if let Some(storage) = storage_meta + && !task.flags.is_restored(TaskDataCategory::Meta) + { + task.restore_from(storage, TaskDataCategory::Meta); + task.flags.set_restored(TaskDataCategory::Meta); } } } @@ -510,32 +525,60 @@ where } let (mut task1, mut task2) = self.backend.storage.access_pair_mut(task_id1, task_id2); - let is_restored1 = task1.state().is_restored(category); - let is_restored2 = task2.state().is_restored(category); - if !is_restored1 || !is_restored2 { - for category in category { - // Avoid holding the lock too long since this can also affect other tasks - drop(task1); - drop(task2); - - let items1 = (!is_restored1).then(|| self.restore_task_data(task_id1, category)); - let items2 = (!is_restored2).then(|| self.restore_task_data(task_id2, category)); - - let (t1, t2) = self.backend.storage.access_pair_mut(task_id1, task_id2); - task1 = t1; - task2 = t2; - if !task1.state().is_restored(category) { - for item in items1.unwrap() { - task1.add(item); - } - task1.state_mut().set_restored(category); - } - if !task2.state().is_restored(category) { - for item in items2.unwrap() { - task2.add(item); - } - task2.state_mut().set_restored(category); - } + + // Collect what needs restoring for each task + let needs_data1 = + category.includes_data() && !task1.flags.is_restored(TaskDataCategory::Data); + let needs_meta1 = + category.includes_meta() && !task1.flags.is_restored(TaskDataCategory::Meta); + let needs_data2 = + category.includes_data() && !task2.flags.is_restored(TaskDataCategory::Data); + let needs_meta2 = + category.includes_meta() && !task2.flags.is_restored(TaskDataCategory::Meta); + + if needs_data1 || needs_meta1 || needs_data2 || needs_meta2 { + // Avoid holding the lock too long since this can also affect other tasks + // Drop locks once, do all I/O, then re-acquire once + drop(task1); + drop(task2); + + let storage_data1 = needs_data1 + .then(|| self.restore_task_data(task_id1, SpecificTaskDataCategory::Data)); + let storage_meta1 = needs_meta1 + .then(|| self.restore_task_data(task_id1, SpecificTaskDataCategory::Meta)); + let storage_data2 = needs_data2 + .then(|| self.restore_task_data(task_id2, SpecificTaskDataCategory::Data)); + let storage_meta2 = needs_meta2 + .then(|| self.restore_task_data(task_id2, SpecificTaskDataCategory::Meta)); + + let (t1, t2) = self.backend.storage.access_pair_mut(task_id1, task_id2); + task1 = t1; + task2 = t2; + + // Merge results, handling race conditions + if let Some(storage) = storage_data1 + && !task1.flags.is_restored(TaskDataCategory::Data) + { + task1.restore_from(storage, TaskDataCategory::Data); + task1.flags.set_restored(TaskDataCategory::Data); + } + if let Some(storage) = storage_meta1 + && !task1.flags.is_restored(TaskDataCategory::Meta) + { + task1.restore_from(storage, TaskDataCategory::Meta); + task1.flags.set_restored(TaskDataCategory::Meta); + } + if let Some(storage) = storage_data2 + && !task2.flags.is_restored(TaskDataCategory::Data) + { + task2.restore_from(storage, TaskDataCategory::Data); + task2.flags.set_restored(TaskDataCategory::Data); + } + if let Some(storage) = storage_meta2 + && !task2.flags.is_restored(TaskDataCategory::Meta) + { + task2.restore_from(storage, TaskDataCategory::Meta); + task2.flags.set_restored(TaskDataCategory::Meta); } } ( @@ -627,56 +670,9 @@ impl<'e, B: BackingStorage> ChildExecuteContext<'e> for ChildExecuteContextImpl< } } -pub trait TaskGuard: Debug { +pub trait TaskGuard: Debug + TaskStorageAccessors { fn id(&self) -> TaskId; - /// Adds a new item to the task if the key is not already present. - /// Returns `true` if the item was added. - /// Returns `false` if an item with the same key was already present. - #[must_use] - fn add(&mut self, item: CachedDataItem) -> bool; - /// Adds a new item to the task. The key must not be already present. - /// Might panic if the key is already present. - fn add_new(&mut self, item: CachedDataItem); - /// Extends the task with items from the iterator. - /// Overwrites existing keys. - /// Returns `true` if all items were new and added. - /// Returns `false` if any item had a key that was already present. - fn extend( - &mut self, - ty: CachedDataItemType, - items: impl Iterator, - ) -> bool; - /// Extends the task with items from the iterator. - /// Might panic if any item has a key that is already present. - fn extend_new(&mut self, ty: CachedDataItemType, items: impl Iterator); - fn insert(&mut self, item: CachedDataItem) -> Option; - fn update( - &mut self, - key: CachedDataItemKey, - update: impl FnOnce(Option) -> Option, - ); - fn remove(&mut self, key: &CachedDataItemKey) -> Option; - fn get(&self, key: &CachedDataItemKey) -> Option>; - fn get_mut(&mut self, key: &CachedDataItemKey) -> Option>; - fn get_mut_or_insert_with( - &mut self, - key: CachedDataItemKey, - insert: impl FnOnce() -> CachedDataItemValue, - ) -> CachedDataItemValueRefMut<'_>; - fn has_key(&self, key: &CachedDataItemKey) -> bool; - fn count(&self, ty: CachedDataItemType) -> usize; - fn iter( - &self, - ty: CachedDataItemType, - ) -> impl Iterator)>; - fn shrink_to_fit(&mut self, ty: CachedDataItemType); - fn extract_if<'l, F>( - &'l mut self, - ty: CachedDataItemType, - f: F, - ) -> impl Iterator - where - F: for<'a> FnMut(CachedDataItemKey, CachedDataItemValueRef<'a>) -> bool + 'l; + fn invalidate_serialization(&mut self); /// Determine which tasks to prefetch for a task. /// Only returns Some once per task. @@ -841,9 +837,7 @@ impl Debug for TaskGuardImpl<'_, B> { if let Some(task_type) = self.backend.task_cache.lookup_reverse(&self.task_id) { d.field("task_type", &task_type); }; - for (key, value) in self.task.iter_all() { - d.field(&format!("{key:?}"), &value); - } + d.field("storage", &*self.task); d.finish() } } @@ -853,167 +847,6 @@ impl TaskGuard for TaskGuardImpl<'_, B> { self.task_id } - #[track_caller] - fn add(&mut self, item: CachedDataItem) -> bool { - let category = item.category(); - self.check_access(category); - if !self.task_id.is_transient() && item.is_persistent() { - if self.task.contains_key(&item.key()) { - return false; - } - self.task.track_modification(category.into_specific()); - } - self.task.add(item) - } - - #[track_caller] - fn add_new(&mut self, item: CachedDataItem) { - let category = item.category(); - self.check_access(category); - if !self.task_id.is_transient() && item.is_persistent() { - self.task.track_modification(category.into_specific()); - } - let added = self.task.add(item); - assert!(added, "Item already exists"); - } - - #[track_caller] - fn extend( - &mut self, - ty: CachedDataItemType, - items: impl Iterator, - ) -> bool { - let category = ty.category(); - self.check_access(category); - if !self.task_id.is_transient() && ty.is_persistent() { - let mut items = items.peekable(); - // Check if the iterator is empty - if items.peek().is_none() { - return true; - } - // TODO this is not optimal as we always track a modification even if nothing is changed - self.task.track_modification(category.into_specific()); - self.task.extend(ty, items) - } else { - self.task.extend(ty, items) - } - } - - #[track_caller] - fn extend_new(&mut self, ty: CachedDataItemType, items: impl Iterator) { - let category = ty.category(); - self.check_access(category); - if !self.task_id.is_transient() && ty.is_persistent() { - self.task.track_modification(category.into_specific()); - } - - let added = self.task.extend(ty, items); - assert!(added, "At least one item already exists"); - } - - #[track_caller] - fn insert(&mut self, item: CachedDataItem) -> Option { - let category = item.category(); - self.check_access(category); - if !self.task_id.is_transient() && item.is_persistent() { - self.task.track_modification(category.into_specific()); - } - self.task.insert(item) - } - - #[track_caller] - fn update( - &mut self, - key: CachedDataItemKey, - update: impl FnOnce(Option) -> Option, - ) { - let category = key.category(); - self.check_access(category); - if !self.task_id.is_transient() && key.is_persistent() { - self.task.track_modification(category.into_specific()); - } - self.task.update(key, update); - } - - #[track_caller] - fn remove(&mut self, key: &CachedDataItemKey) -> Option { - let category = key.category(); - self.check_access(category); - if !self.task_id.is_transient() && key.is_persistent() { - self.task.track_modification(category.into_specific()); - } - self.task.remove(key) - } - - fn get(&self, key: &CachedDataItemKey) -> Option> { - self.check_access(key.category()); - self.task.get(key) - } - - #[track_caller] - fn get_mut(&mut self, key: &CachedDataItemKey) -> Option> { - let category = key.category(); - self.check_access(category); - if !self.task_id.is_transient() && key.is_persistent() { - self.task.track_modification(category.into_specific()); - } - self.task.get_mut(key) - } - - #[track_caller] - fn get_mut_or_insert_with( - &mut self, - key: CachedDataItemKey, - insert: impl FnOnce() -> CachedDataItemValue, - ) -> CachedDataItemValueRefMut<'_> { - let category = key.category(); - self.check_access(category); - if !self.task_id.is_transient() && key.is_persistent() { - self.task.track_modification(category.into_specific()); - } - self.task.get_mut_or_insert_with(key, insert) - } - - #[track_caller] - fn has_key(&self, key: &CachedDataItemKey) -> bool { - self.check_access(key.category()); - self.task.contains_key(key) - } - - #[track_caller] - fn count(&self, ty: CachedDataItemType) -> usize { - self.check_access(ty.category()); - self.task.count(ty) - } - - fn iter( - &self, - ty: CachedDataItemType, - ) -> impl Iterator)> { - self.check_access(ty.category()); - self.task.iter(ty) - } - - fn shrink_to_fit(&mut self, ty: CachedDataItemType) { - self.task.shrink_to_fit(ty) - } - - #[track_caller] - fn extract_if<'l, F>( - &'l mut self, - ty: CachedDataItemType, - f: F, - ) -> impl Iterator - where - F: for<'a> FnMut(CachedDataItemKey, CachedDataItemValueRef<'a>) -> bool + 'l, - { - self.check_access(ty.category()); - if !self.task_id.is_transient() && ty.is_persistent() { - self.task.track_modification(ty.category().into_specific()); - } - self.task.extract_if(ty, f) - } - fn invalidate_serialization(&mut self) { // TODO this causes race conditions, since we never know when a value is changed. We can't // "snapshot" the value correctly. @@ -1024,10 +857,10 @@ impl TaskGuard for TaskGuardImpl<'_, B> { } fn prefetch(&mut self) -> Option> { - if self.task.state().prefetched() { + if self.task.flags.prefetched() { return None; } - self.task.state_mut().set_prefetched(true); + self.task.flags.set_prefetched(true); let map = iter_many!(self, OutputDependency { target } => (target, TaskDataCategory::Meta)) .chain(iter_many!(self, CellDependency { target, key: _ } => (target.task, TaskDataCategory::All))) .chain(iter_many!(self, CollectiblesDependency { target } => (target.task, TaskDataCategory::All))) @@ -1037,6 +870,26 @@ impl TaskGuard for TaskGuardImpl<'_, B> { } } +impl<'a, B: BackingStorage> TaskStorageAccessors for TaskGuardImpl<'a, B> { + fn typed(&self) -> &TaskStorage { + &self.task + } + + fn typed_mut(&mut self) -> &mut TaskStorage { + &mut self.task + } + + fn track_modification(&mut self, category: crate::backend::storage::SpecificTaskDataCategory) { + if !self.task_id.is_transient() { + self.task.track_modification(category); + } + } + + fn check_access(&self, category: crate::backend::TaskDataCategory) { + self.check_access(category); + } +} + macro_rules! impl_operation { ($name:ident $type_path:path) => { impl From<$type_path> for AnyOperation { @@ -1072,7 +925,7 @@ pub enum AnyOperation { } impl AnyOperation { - pub fn execute(self, ctx: &mut impl ExecuteContext) { + pub fn execute(self, ctx: &mut impl ExecuteContext<'_>) { match self { AnyOperation::ConnectChild(op) => op.execute(ctx), AnyOperation::Invalidate(op) => op.execute(ctx), diff --git a/turbopack/crates/turbo-tasks-backend/src/backend/operation/update_cell.rs b/turbopack/crates/turbo-tasks-backend/src/backend/operation/update_cell.rs index c76df6b0a594cd..4df884e8d54131 100644 --- a/turbopack/crates/turbo-tasks-backend/src/backend/operation/update_cell.rs +++ b/turbopack/crates/turbo-tasks-backend/src/backend/operation/update_cell.rs @@ -12,7 +12,7 @@ use turbo_tasks::{CellId, FxIndexMap, TaskId, TypedSharedReference, backend::Cel use crate::backend::operation::invalidate::TaskDirtyCause; use crate::{ backend::{ - TaskDataCategory, + TaskDataCategory, TaskStorageAccessors, operation::{ AggregationUpdateQueue, ExecuteContext, Operation, TaskGuard, invalidate::make_task_dirty_internal, diff --git a/turbopack/crates/turbo-tasks-backend/src/backend/storage.rs b/turbopack/crates/turbo-tasks-backend/src/backend/storage.rs index f66286329b320c..a3caec38404a25 100644 --- a/turbopack/crates/turbo-tasks-backend/src/backend/storage.rs +++ b/turbopack/crates/turbo-tasks-backend/src/backend/storage.rs @@ -4,18 +4,12 @@ use std::{ sync::{Arc, atomic::AtomicBool}, }; -use bitfield::bitfield; use smallvec::SmallVec; use turbo_tasks::{FxDashMap, TaskId, parallel}; use crate::{ - backend::dynamic_storage::DynamicStorage, - data::{ - AggregationNumber, CachedDataItem, CachedDataItemKey, CachedDataItemType, - CachedDataItemValue, CachedDataItemValueRef, CachedDataItemValueRefMut, LeafDistance, - OutputValue, - }, - data_storage::{AutoMapStorage, DefaultStorage, OptionStorage}, + backend::storage_schema::TaskStorage, + database::key_value_database::KeySpace, utils::{ dash_map_drop_contents::drop_contents, dash_map_multi::{RefMut, get_multiple_mut}, @@ -37,621 +31,30 @@ impl TaskDataCategory { TaskDataCategory::All => unreachable!(), } } -} - -#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] -pub enum SpecificTaskDataCategory { - Meta, - Data, -} -impl IntoIterator for TaskDataCategory { - type Item = TaskDataCategory; - - type IntoIter = TaskDataCategoryIterator; + pub fn includes_data(self) -> bool { + matches!(self, TaskDataCategory::Data | TaskDataCategory::All) + } - fn into_iter(self) -> Self::IntoIter { - match self { - TaskDataCategory::Meta => TaskDataCategoryIterator::Meta, - TaskDataCategory::Data => TaskDataCategoryIterator::Data, - TaskDataCategory::All => TaskDataCategoryIterator::All, - } + pub fn includes_meta(self) -> bool { + matches!(self, TaskDataCategory::Meta | TaskDataCategory::All) } } -pub enum TaskDataCategoryIterator { - All, +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +pub enum SpecificTaskDataCategory { Meta, Data, - None, } -impl Iterator for TaskDataCategoryIterator { - type Item = TaskDataCategory; - - fn next(&mut self) -> Option { +impl SpecificTaskDataCategory { + /// Returns the KeySpace for storing data of this category + pub fn key_space(self) -> KeySpace { match self { - TaskDataCategoryIterator::All => { - *self = TaskDataCategoryIterator::Data; - Some(TaskDataCategory::Meta) - } - TaskDataCategoryIterator::Meta => { - *self = TaskDataCategoryIterator::None; - Some(TaskDataCategory::Meta) - } - TaskDataCategoryIterator::Data => { - *self = TaskDataCategoryIterator::None; - Some(TaskDataCategory::Data) - } - TaskDataCategoryIterator::None => None, - } - } -} - -bitfield! { - // Note: Due to alignment in InnerStorage it doesn't matter if this struct is 1 or 4 bytes. - #[derive(Clone, Default)] - pub struct InnerStorageState(u32); - impl Debug; - pub meta_restored, set_meta_restored: 0; - pub data_restored, set_data_restored: 1; - /// Item was modified before snapshot mode was entered. - pub meta_modified, set_meta_modified: 2; - pub data_modified, set_data_modified: 3; - /// Item was modified after snapshot mode was entered. A snapshot was taken. - pub meta_snapshot, set_meta_snapshot: 4; - pub data_snapshot, set_data_snapshot: 5; - /// Prefetched dependencies - pub prefetched, set_prefetched: 6; -} - -impl InnerStorageState { - pub fn set_restored(&mut self, category: TaskDataCategory) { - match category { - TaskDataCategory::Meta => { - self.set_meta_restored(true); - } - TaskDataCategory::Data => { - self.set_data_restored(true); - } - TaskDataCategory::All => { - self.set_meta_restored(true); - self.set_data_restored(true); - } - } - } - - pub fn is_restored(&self, category: TaskDataCategory) -> bool { - match category { - TaskDataCategory::Meta => self.meta_restored(), - TaskDataCategory::Data => self.data_restored(), - TaskDataCategory::All => self.meta_restored() && self.data_restored(), - } - } - - pub fn any_snapshot(&self) -> bool { - self.meta_snapshot() || self.data_snapshot() - } - - pub fn any_modified(&self) -> bool { - self.meta_modified() || self.data_modified() - } -} - -pub struct InnerStorageSnapshot { - leaf_distance: DefaultStorage, - aggregation_number: DefaultStorage, - output_dependent: AutoMapStorage, - output: OptionStorage, - upper: AutoMapStorage, - dynamic: DynamicStorage, - pub meta_modified: bool, - pub data_modified: bool, -} - -impl From<&InnerStorage> for InnerStorageSnapshot { - fn from(inner: &InnerStorage) -> Self { - Self { - leaf_distance: inner.leaf_distance.clone(), - aggregation_number: inner.aggregation_number.clone(), - output_dependent: inner.output_dependent.clone(), - output: inner.output.clone(), - upper: inner.upper.clone(), - dynamic: inner.dynamic.snapshot_for_persisting(), - meta_modified: inner.state.meta_modified(), - data_modified: inner.state.data_modified(), - } - } -} - -impl InnerStorageSnapshot { - pub fn iter_all( - &self, - ) -> impl Iterator)> { - use crate::data_storage::Storage; - self.dynamic - .iter_all() - .chain(self.leaf_distance.iter().map(|(_, value)| { - ( - CachedDataItemKey::LeafDistance {}, - CachedDataItemValueRef::LeafDistance { value }, - ) - })) - .chain(self.aggregation_number.iter().map(|(_, value)| { - ( - CachedDataItemKey::AggregationNumber {}, - CachedDataItemValueRef::AggregationNumber { value }, - ) - })) - .chain(self.output.iter().map(|(_, value)| { - ( - CachedDataItemKey::Output {}, - CachedDataItemValueRef::Output { value }, - ) - })) - .chain(self.upper.iter().map(|(k, value)| { - ( - CachedDataItemKey::Upper { task: *k }, - CachedDataItemValueRef::Upper { value }, - ) - })) - .chain(self.output_dependent.iter().map(|(k, value)| { - ( - CachedDataItemKey::OutputDependent { task: *k }, - CachedDataItemValueRef::OutputDependent { value }, - ) - })) - } - - pub fn len(&self) -> usize { - use crate::data_storage::Storage; - self.dynamic.len() - + self.leaf_distance.len() - + self.aggregation_number.len() - + self.output.len() - + self.upper.len() - + self.output_dependent.len() - } -} - -#[derive(Debug, Clone)] -pub struct InnerStorage { - leaf_distance: DefaultStorage, - aggregation_number: DefaultStorage, - output_dependent: AutoMapStorage, - output: OptionStorage, - upper: AutoMapStorage, - dynamic: DynamicStorage, - state: InnerStorageState, -} - -impl InnerStorage { - fn new() -> Self { - Self { - leaf_distance: Default::default(), - aggregation_number: Default::default(), - output_dependent: Default::default(), - output: Default::default(), - upper: Default::default(), - dynamic: DynamicStorage::new(), - state: InnerStorageState::default(), + SpecificTaskDataCategory::Meta => KeySpace::TaskMeta, + SpecificTaskDataCategory::Data => KeySpace::TaskData, } } - - pub fn state(&self) -> &InnerStorageState { - &self.state - } - - pub fn state_mut(&mut self) -> &mut InnerStorageState { - &mut self.state - } -} - -#[macro_export] -macro_rules! generate_inner_storage_internal { - // Matching on CachedDataItem with a $value - (CachedDataItem: $self:ident, $item:ident, $value:ident, $return_ty:tt, $fn:ident($($args:tt)*): $tag:ident $key_field:ident => $field:ident,) => { - if let CachedDataItem::$tag { $key_field, $value } = $item { - let result = $self.$field.$fn($key_field, $($args)*); - return $crate::generate_inner_storage_internal!(return_value: result, $return_ty: $tag $key_field => $field); - } - }; - (CachedDataItem: $self:ident, $item:ident, $value:ident, $return_ty:tt, $fn:ident($($args:tt)*): $tag:ident => $field:ident,) => { - if let CachedDataItem::$tag { $value } = $item { - let result = $self.$field.$fn((), $($args)*); - return $crate::generate_inner_storage_internal!(return_value: result, $return_ty: $tag => $field); - } - }; - (CachedDataItem: $self:ident, $item:ident, $value:ident, $return_ty:tt, $fn:ident($($args:tt)*): $tag:ident $($key_field:ident)? => $field:ident, $($config:tt)+) => { - $crate::generate_inner_storage_internal!(CachedDataItem: $self, $item, $value, $return_ty, $fn($($args)*): $tag $($key_field)? => $field,); - $crate::generate_inner_storage_internal!(CachedDataItem: $self, $item, $value, $return_ty, $fn($($args)*): $($config)+) - }; - // Matching on CachedDataItemKey without a $value - (CachedDataItemKey: $self:ident, $item:ident, $return_ty:tt, $fn:ident($($args:tt)*): $tag:ident $key_field:ident => $field:ident,) => { - if let CachedDataItemKey::$tag { $key_field } = $item { - let result = $self.$field.$fn($key_field, $($args)*); - return $crate::generate_inner_storage_internal!(return_value: result, $return_ty: $tag $key_field => $field); - } - }; - (CachedDataItemKey: $self:ident, $item:ident, $return_ty:tt, $fn:ident($($args:tt)*): $tag:ident => $field:ident,) => { - if let CachedDataItemKey::$tag { } = $item { - let result = $self.$field.$fn(&(), $($args)*); - return $crate::generate_inner_storage_internal!(return_value: result, $return_ty: $tag => $field); - } - }; - (CachedDataItemKey: $self:ident, $item:ident, $return_ty:tt, $fn:ident($($args:tt)*): $tag:ident $($key_field:ident)? => $field:ident, $($config:tt)+) => { - $crate::generate_inner_storage_internal!(CachedDataItemKey: $self, $item, $return_ty, $fn($($args)*): $tag $($key_field)? => $field,); - $crate::generate_inner_storage_internal!(CachedDataItemKey: $self, $item, $return_ty, $fn($($args)*): $($config)+) - }; - // Matching on CachedDataItemType without a $value - (CachedDataItemType: $self:ident, $item:ident, $return_ty:tt, $fn:ident($($args:tt)*): $tag:ident $($key_field:ident)? => $field:ident,) => { - if let CachedDataItemType::$tag = $item { - let result = $self.$field.$fn($($args)*); - return $crate::generate_inner_storage_internal!(return_value: result, $return_ty: $tag $($key_field)? => $field); - } - }; - (CachedDataItemType: $self:ident, $item:ident, $return_ty:tt, $fn:ident($($args:tt)*): $tag:ident $($key_field:ident)? => $field:ident, $($config:tt)+) => { - $crate::generate_inner_storage_internal!(CachedDataItemType: $self, $item, $return_ty, $fn($($args)*): $tag $($key_field)? => $field,); - $crate::generate_inner_storage_internal!(CachedDataItemType: $self, $item, $return_ty, $fn($($args)*): $($config)+) - }; - - // fn update - (update: $self:ident, $key:ident, $update:ident: $tag:ident $key_field:ident => $field:ident,) => { - if let CachedDataItemKey::$tag { $key_field } = $key { - $self.$field.update($key_field, |old| { - let old = old.map(|old| CachedDataItemValue::$tag { value: old }); - let new = $update(old); - new.map(|new| if let CachedDataItemValue::$tag { value } = new { - value - } else { - unreachable!() - }) - }); - return; - } - }; - (update: $self:ident, $key:ident, $update:ident: $tag:ident => $field:ident,) => { - if let CachedDataItemKey::$tag { } = $key { - $self.$field.update((), |old| { - let old = old.map(|old| CachedDataItemValue::$tag { value: old }); - let new = $update(old); - new.map(|new| if let CachedDataItemValue::$tag { value } = new { - value - } else { - unreachable!() - }) - }); - return; - } - }; - (update: $self:ident, $key:ident, $update:ident: $tag:ident $($key_field:ident)? => $field:ident, $($config:tt)+) => { - $crate::generate_inner_storage_internal!(update: $self, $key, $update: $tag $($key_field)? => $field,); - $crate::generate_inner_storage_internal!(update: $self, $key, $update: $($config)+) - }; - - // fn extend - (extend: $self:ident, $ty:ident, $items:ident: $tag:ident $key_field:ident => $field:ident,) => { - if let CachedDataItemType::$tag = $ty { - return $self.$field.extend($items.map(|item| { - let pair = turbo_tasks::KeyValuePair::into_key_and_value(item); - if let (CachedDataItemKey::$tag { $key_field }, CachedDataItemValue::$tag { value }) = pair { - ($key_field, value) - } else { - unreachable!() - } - })); - } - }; - (extend: $self:ident, $ty:ident, $items:ident: $tag:ident => $field:ident,) => { - if let CachedDataItemType::$tag = $ty { - return $self.$field.extend($items.map(|item| { - let pair = turbo_tasks::KeyValuePair::into_key_and_value(item); - if let (_, CachedDataItemValue::$tag { value }) = pair { - ((), value) - } else { - unreachable!() - } - })); - } - }; - (extend: $self:ident, $ty:ident, $items:ident: $tag:ident $($key_field:ident)? => $field:ident, $($config:tt)+) => { - $crate::generate_inner_storage_internal!(extend: $self, $ty, $items: $tag $($key_field)? => $field,); - $crate::generate_inner_storage_internal!(extend: $self, $ty, $items: $($config)+) - }; - - // fn get_mut_or_insert_with - (get_mut_or_insert_with: $self:ident, $key:ident, $insert_with:ident: $tag:ident $key_field:ident => $field:ident,) => { - if let CachedDataItemKey::$tag { $key_field } = $key { - let value = $self.$field.get_mut_or_insert_with($key_field, || { - let value = $insert_with(); - if let CachedDataItemValue::$tag { value } = value { - value - } else { - unreachable!() - } - }); - return CachedDataItemValueRefMut::$tag { value }; - } - }; - (get_mut_or_insert_with: $self:ident, $key:ident, $insert_with:ident: $tag:ident => $field:ident,) => { - if let CachedDataItemKey::$tag { } = $key { - let value = $self.$field.get_mut_or_insert_with((), || { - let value = $insert_with(); - if let CachedDataItemValue::$tag { value } = value { - value - } else { - unreachable!() - } - }); - return CachedDataItemValueRefMut::$tag { value }; - } - }; - (get_mut_or_insert_with: $self:ident, $key:ident, $insert_with:ident: $tag:ident $($key_field:ident)? => $field:ident, $($config:tt)+) => { - $crate::generate_inner_storage_internal!(get_mut_or_insert_with: $self, $key, $insert_with: $tag $($key_field)? => $field,); - $crate::generate_inner_storage_internal!(get_mut_or_insert_with: $self, $key, $insert_with: $($config)+) - }; - - // fn extract_if - (extract_if: $self:ident, $ty:ident, $f:ident: $tag:ident $key_field:ident => $field:ident,) => { - if let CachedDataItemType::$tag = $ty { - let iter = $self.$field.extract_if(move |key, value| { - $f(CachedDataItemKey::$tag { $key_field: *key }, CachedDataItemValueRef::$tag { value }) - }).map(|($key_field, value)| CachedDataItem::$tag { $key_field, value }); - return InnerStorageIter::$tag(iter); - } - }; - (extract_if: $self:ident, $ty:ident, $f:ident: $tag:ident => $field:ident,) => { - if let CachedDataItemType::$tag = $ty { - let iter = $self.$field.extract_if(move |_, value| { - $f(CachedDataItemKey::$tag { }, CachedDataItemValueRef::$tag { value }) - }).map(|(_, value)| CachedDataItem::$tag { value }); - return InnerStorageIter::$tag(iter); - } - }; - (extract_if: $self:ident, $ty:ident, $f:ident: $tag:ident $($key_field:ident)? => $field:ident, $($config:tt)+) => { - $crate::generate_inner_storage_internal!(extract_if: $self, $ty, $f: $tag $($key_field)? => $field,); - $crate::generate_inner_storage_internal!(extract_if: $self, $ty, $f: $($config)+) - }; - - // fn iter - (iter: $self:ident, $ty:ident: $tag:ident $key_field:ident => $field:ident,) => { - if let CachedDataItemType::$tag = $ty { - let iter = $self.$field.iter().map(|($key_field, value)| (CachedDataItemKey::$tag { $key_field: *$key_field }, CachedDataItemValueRef::$tag { value })); - return InnerStorageIter::$tag(iter); - } - }; - (iter: $self:ident, $ty:ident: $tag:ident => $field:ident,) => { - if let CachedDataItemType::$tag = $ty { - let iter = $self.$field.iter().map(|(_, value)| (CachedDataItemKey::$tag { }, CachedDataItemValueRef::$tag { value })); - return InnerStorageIter::$tag(iter); - } - }; - (iter: $self:ident, $ty:ident: $tag:ident $($key_field:ident)? => $field:ident, $($config:tt)+) => { - $crate::generate_inner_storage_internal!(iter: $self, $ty: $tag $($key_field)? => $field,); - $crate::generate_inner_storage_internal!(iter: $self, $ty: $($config)+) - }; - - - // Return value handling - (return_value: $result:ident, none: $($more:tt)*) => { - $result - }; - (return_value: $result:ident, option_value: $tag:ident $($more:tt)*) => { - $result.map(|value| CachedDataItemValue::$tag { value }) - }; - (return_value: $result:ident, option_ref: $tag:ident $($more:tt)*) => { - $result.map(|value| CachedDataItemValueRef::$tag { value }) - }; - (return_value: $result:ident, option_ref_mut: $tag:ident $($more:tt)*) => { - $result.map(|value| CachedDataItemValueRefMut::$tag { value }) - }; - - // Input value handling - (input_value: $input:ident, option_value: $tag:ident $($more:tt)*) => { - $input.map(|value| { - if let CachedDataItemValue::$tag { value } = value { - value - } else { - unreachable!() - } - }) - }; - -} - -macro_rules! generate_inner_storage { - ($($config:tt)*) => { - impl InnerStorage { - pub fn add(&mut self, item: CachedDataItem) -> bool { - use crate::data_storage::Storage; - $crate::generate_inner_storage_internal!(CachedDataItem: self, item, value, none, add(value): $($config)*); - self.dynamic.add(item) - } - - pub fn extend(&mut self, ty: CachedDataItemType, items: impl Iterator) -> bool { - use crate::data_storage::Storage; - $crate::generate_inner_storage_internal!(extend: self, ty, items: $($config)*); - self.dynamic.extend(ty, items) - } - - pub fn insert(&mut self, item: CachedDataItem) -> Option { - use crate::data_storage::Storage; - $crate::generate_inner_storage_internal!(CachedDataItem: self, item, value, option_value, insert(value): $($config)*); - self.dynamic.insert(item) - } - - pub fn remove(&mut self, key: &CachedDataItemKey) -> Option { - use crate::data_storage::Storage; - $crate::generate_inner_storage_internal!(CachedDataItemKey: self, key, option_value, remove(): $($config)*); - self.dynamic.remove(key) - } - - pub fn count(&self, ty: CachedDataItemType) -> usize { - use crate::data_storage::Storage; - $crate::generate_inner_storage_internal!(CachedDataItemType: self, ty, none, len(): $($config)*); - self.dynamic.count(ty) - } - - pub fn get(&self, key: &CachedDataItemKey) -> Option> { - use crate::data_storage::Storage; - $crate::generate_inner_storage_internal!(CachedDataItemKey: self, key, option_ref, get(): $($config)*); - self.dynamic.get(key) - } - - pub fn contains_key(&self, key: &CachedDataItemKey) -> bool { - use crate::data_storage::Storage; - $crate::generate_inner_storage_internal!(CachedDataItemKey: self, key, none, contains_key(): $($config)*); - self.dynamic.contains_key(key) - } - - pub fn get_mut(&mut self, key: &CachedDataItemKey) -> Option> { - use crate::data_storage::Storage; - $crate::generate_inner_storage_internal!(CachedDataItemKey: self, key, option_ref_mut, get_mut(): $($config)*); - self.dynamic.get_mut(key) - } - - pub fn shrink_to_fit(&mut self, ty: CachedDataItemType) { - use crate::data_storage::Storage; - $crate::generate_inner_storage_internal!(CachedDataItemType: self, ty, none, shrink_to_fit(): $($config)*); - self.dynamic.shrink_to_fit(ty) - } - - pub fn update( - &mut self, - key: CachedDataItemKey, - update: impl FnOnce(Option) -> Option, - ) { - use crate::data_storage::Storage; - $crate::generate_inner_storage_internal!(update: self, key, update: $($config)*); - self.dynamic.update(key, update) - } - - pub fn extract_if<'l, F>( - &'l mut self, - ty: CachedDataItemType, - mut f: F, - ) -> impl Iterator + use<'l, F> - where - F: for<'a> FnMut(CachedDataItemKey, CachedDataItemValueRef<'a>) -> bool + 'l, - { - use crate::data_storage::Storage; - $crate::generate_inner_storage_internal!(extract_if: self, ty, f: $($config)*); - InnerStorageIter::Dynamic(self.dynamic.extract_if(ty, f)) - } - - pub fn get_mut_or_insert_with( - &mut self, - key: CachedDataItemKey, - f: impl FnOnce() -> CachedDataItemValue, - ) -> CachedDataItemValueRefMut<'_> - { - use crate::data_storage::Storage; - $crate::generate_inner_storage_internal!(get_mut_or_insert_with: self, key, f: $($config)*); - self.dynamic.get_mut_or_insert_with(key, f) - } - - pub fn iter( - &self, - ty: CachedDataItemType, - ) -> impl Iterator)> - { - use crate::data_storage::Storage; - $crate::generate_inner_storage_internal!(iter: self, ty: $($config)*); - InnerStorageIter::Dynamic(self.dynamic.iter(ty)) - } - - } - }; -} - -generate_inner_storage!( - LeafDistance => leaf_distance, - AggregationNumber => aggregation_number, - OutputDependent task => output_dependent, - Output => output, - Upper task => upper, -); - -enum InnerStorageIter { - LeafDistance(A), - AggregationNumber(B), - OutputDependent(C), - Output(D), - Upper(E), - Dynamic(F), -} - -impl Iterator for InnerStorageIter -where - A: Iterator, - B: Iterator, - C: Iterator, - D: Iterator, - E: Iterator, - F: Iterator, -{ - type Item = T; - - fn next(&mut self) -> Option { - match self { - InnerStorageIter::LeafDistance(iter) => iter.next(), - InnerStorageIter::AggregationNumber(iter) => iter.next(), - InnerStorageIter::OutputDependent(iter) => iter.next(), - InnerStorageIter::Output(iter) => iter.next(), - InnerStorageIter::Upper(iter) => iter.next(), - InnerStorageIter::Dynamic(iter) => iter.next(), - } - } -} - -impl InnerStorage { - pub fn iter_all( - &self, - ) -> impl Iterator)> { - use crate::data_storage::Storage; - self.dynamic - .iter_all() - .chain(self.leaf_distance.iter().map(|(_, value)| { - ( - CachedDataItemKey::LeafDistance {}, - CachedDataItemValueRef::LeafDistance { value }, - ) - })) - .chain(self.aggregation_number.iter().map(|(_, value)| { - ( - CachedDataItemKey::AggregationNumber {}, - CachedDataItemValueRef::AggregationNumber { value }, - ) - })) - .chain(self.output.iter().map(|(_, value)| { - ( - CachedDataItemKey::Output {}, - CachedDataItemValueRef::Output { value }, - ) - })) - .chain(self.upper.iter().map(|(k, value)| { - ( - CachedDataItemKey::Upper { task: *k }, - CachedDataItemValueRef::Upper { value }, - ) - })) - .chain(self.output_dependent.iter().map(|(k, value)| { - ( - CachedDataItemKey::OutputDependent { task: *k }, - CachedDataItemValueRef::OutputDependent { value }, - ) - })) - } - - pub fn len(&self) -> usize { - use crate::data_storage::Storage; - self.dynamic.len() - + self.leaf_distance.len() - + self.aggregation_number.len() - + self.output.len() - + self.upper.len() - + self.output_dependent.len() - } } enum ModifiedState { @@ -664,13 +67,13 @@ enum ModifiedState { /// Snapshot(None): /// It was not modified before snapshot mode was entered, but it was accessed during snapshot /// mode. Or the snapshot was already taken out by the snapshot operation. - Snapshot(Option>), + Snapshot(Option>), } pub struct Storage { snapshot_mode: AtomicBool, modified: FxDashMap, - map: FxDashMap>, + map: FxDashMap>, } impl Storage { @@ -705,9 +108,9 @@ impl Storage { 'l, T, R, - PP: for<'a> Fn(TaskId, &'a InnerStorage) -> T + Sync, + PP: for<'a> Fn(TaskId, &'a TaskStorage) -> T + Sync, P: Fn(TaskId, T) -> R + Sync, - PS: Fn(TaskId, Box) -> R + Sync, + PS: Fn(TaskId, Box) -> R + Sync, >( &'l self, preprocess: &'l PP, @@ -723,7 +126,7 @@ impl Storage { // The number of shards is much larger than the number of threads, so the effect of the // locks held is negligible. parallel::map_collect::<_, _, Vec<_>>(self.modified.shards(), |shard| { - let mut direct_snapshots: Vec<(TaskId, Box)> = Vec::new(); + let mut direct_snapshots: Vec<(TaskId, Box)> = Vec::new(); let mut modified: SmallVec<[TaskId; 4]> = SmallVec::new(); { // Take the snapshots from the modified map @@ -787,9 +190,8 @@ impl Storage { // We also need to unset all the modified flags. for key in removed_modified { if let Some(mut inner) = self.map.get_mut(&key) { - let state = inner.state_mut(); - state.set_data_modified(false); - state.set_meta_modified(false); + inner.flags.set_data_modified(false); + inner.flags.set_meta_modified(false); } } @@ -816,14 +218,13 @@ impl Storage { // And update the flags for key in removed_snapshots { if let Some(mut inner) = self.map.get_mut(&key) { - let state = inner.state_mut(); - if state.meta_snapshot() { - state.set_meta_snapshot(false); - state.set_meta_modified(true); + if inner.flags.meta_snapshot() { + inner.flags.set_meta_snapshot(false); + inner.flags.set_meta_modified(true); } - if state.data_snapshot() { - state.set_data_snapshot(false); - state.set_data_modified(true); + if inner.flags.data_snapshot() { + inner.flags.set_data_snapshot(false); + inner.flags.set_data_modified(true); } } } @@ -840,7 +241,7 @@ impl Storage { pub fn access_mut(&self, key: TaskId) -> StorageWriteGuard<'_> { let inner = match self.map.entry(key) { dashmap::mapref::entry::Entry::Occupied(e) => e.into_ref(), - dashmap::mapref::entry::Entry::Vacant(e) => e.insert(Box::new(InnerStorage::new())), + dashmap::mapref::entry::Entry::Vacant(e) => e.insert(Box::new(TaskStorage::new())), }; StorageWriteGuard { storage: self, @@ -853,7 +254,7 @@ impl Storage { key1: TaskId, key2: TaskId, ) -> (StorageWriteGuard<'_>, StorageWriteGuard<'_>) { - let (a, b) = get_multiple_mut(&self.map, key1, key2, || Box::new(InnerStorage::new())); + let (a, b) = get_multiple_mut(&self.map, key1, key2, || Box::new(TaskStorage::new())); ( StorageWriteGuard { storage: self, @@ -874,75 +275,61 @@ impl Storage { pub struct StorageWriteGuard<'a> { storage: &'a Storage, - inner: RefMut<'a, TaskId, Box>, + inner: RefMut<'a, TaskId, Box>, } impl StorageWriteGuard<'_> { /// Tracks mutation of this task pub fn track_modification(&mut self, category: SpecificTaskDataCategory) { - let state = self.inner.state(); - let snapshot = match category { - SpecificTaskDataCategory::Meta => state.meta_snapshot(), - SpecificTaskDataCategory::Data => state.data_snapshot(), - }; - if !snapshot { - let modified = match category { - SpecificTaskDataCategory::Meta => state.meta_modified(), - SpecificTaskDataCategory::Data => state.data_modified(), - }; - match (self.storage.snapshot_mode(), modified) { - (false, false) => { - // Not in snapshot mode and item is unmodified - if !state.any_snapshot() && !state.any_modified() { - self.storage - .modified - .insert(*self.inner.key(), ModifiedState::Modified); - } - let state = self.inner.state_mut(); - match category { - SpecificTaskDataCategory::Meta => state.set_meta_modified(true), - SpecificTaskDataCategory::Data => state.set_data_modified(true), - } + let flags = &self.inner.flags; + if flags.is_snapshot(category) { + return; + } + let modified = flags.is_modified(category); + match (self.storage.snapshot_mode(), modified) { + (false, false) => { + // Not in snapshot mode and item is unmodified + if !flags.any_snapshot() && !flags.any_modified() { + self.storage + .modified + .insert(*self.inner.key(), ModifiedState::Modified); } - (false, true) => { - // Not in snapshot mode and item is already modified - // Do nothing + self.inner.flags.set_modified(category, true); + } + (false, true) => { + // Not in snapshot mode and item is already modified + // Do nothing + } + (true, false) => { + // In snapshot mode and item is unmodified (so it's not part of the snapshot) + if !flags.any_snapshot() { + self.storage + .modified + .insert(*self.inner.key(), ModifiedState::Snapshot(None)); } - (true, false) => { - // In snapshot mode and item is unmodified (so it's not part of the snapshot) - if !state.any_snapshot() { - self.storage - .modified - .insert(*self.inner.key(), ModifiedState::Snapshot(None)); - } - let state = self.inner.state_mut(); - match category { - SpecificTaskDataCategory::Meta => state.set_meta_snapshot(true), - SpecificTaskDataCategory::Data => state.set_data_snapshot(true), - } - } - (true, true) => { - // In snapshot mode and item is modified (so it's part of the snapshot) - // We need to store the original version that is part of the snapshot - if !state.any_snapshot() { - self.storage.modified.insert( - *self.inner.key(), - ModifiedState::Snapshot(Some(Box::new((&**self.inner).into()))), - ); - } - let state = self.inner.state_mut(); - match category { - SpecificTaskDataCategory::Meta => state.set_meta_snapshot(true), - SpecificTaskDataCategory::Data => state.set_data_snapshot(true), - } + self.inner.flags.set_snapshot(category, true); + } + (true, true) => { + // In snapshot mode and item is modified (so it's part of the snapshot) + // We need to store the original version that is part of the snapshot + if !flags.any_snapshot() { + // Snapshot all non-transient fields but keep the modified bits. + let mut snapshot = self.inner.clone_snapshot(); + snapshot.flags.set_data_modified(flags.data_modified()); + snapshot.flags.set_meta_modified(flags.meta_modified()); + self.storage.modified.insert( + *self.inner.key(), + ModifiedState::Snapshot(Some(Box::new(snapshot))), + ); } + self.inner.flags.set_snapshot(category, true); } } } } impl Deref for StorageWriteGuard<'_> { - type Target = InnerStorage; + type Target = TaskStorage; fn deref(&self) -> &Self::Target { &self.inner @@ -955,6 +342,27 @@ impl DerefMut for StorageWriteGuard<'_> { } } +// TODO: this implementation is only needed to bootstrap new tasks +impl super::storage_schema::TaskStorageAccessors for StorageWriteGuard<'_> { + fn typed(&self) -> &super::storage_schema::TaskStorage { + &self.inner + } + + fn typed_mut(&mut self) -> &mut super::storage_schema::TaskStorage { + &mut self.inner + } + + fn track_modification(&mut self, category: SpecificTaskDataCategory) { + // Delegate to the existing track_modification method + StorageWriteGuard::track_modification(self, category) + } + + fn check_access(&self, _category: super::TaskDataCategory) { + // StorageWriteGuard doesn't have category tracking - that's handled by TaskGuardImpl. + // This is a no-op for Stor + } +} + macro_rules! count { ($task:ident, $key:ident) => {{ $task.count($crate::data::CachedDataItemType::$key) }}; } @@ -962,7 +370,7 @@ macro_rules! count { macro_rules! get { ($task:ident, $key:ident $input:tt) => {{ #[allow(unused_imports)] - use $crate::backend::operation::TaskGuard; + use $crate::backend::storage_schema::TaskStorageAccessors; if let Some($crate::data::CachedDataItemValueRef::$key { value, }) = $task.get(&$crate::data::CachedDataItemKey::$key $input) { @@ -979,7 +387,7 @@ macro_rules! get { macro_rules! get_mut { ($task:ident, $key:ident $input:tt) => {{ #[allow(unused_imports)] - use $crate::backend::operation::TaskGuard; + use $crate::backend::storage_schema::TaskStorageAccessors; if let Some($crate::data::CachedDataItemValueRefMut::$key { value, }) = $task.get_mut(&$crate::data::CachedDataItemKey::$key $input) { @@ -1020,7 +428,7 @@ macro_rules! get_mut_or_insert_with { macro_rules! iter_many { ($task:ident, $key:ident $key_pattern:tt $(if $cond:expr)? => $iter_item:expr) => {{ #[allow(unused_imports)] - use $crate::backend::operation::TaskGuard; + use $crate::backend::storage_schema::TaskStorageAccessors; $task .iter($crate::data::CachedDataItemType::$key) .filter_map(|(key, _)| match key { @@ -1032,7 +440,7 @@ macro_rules! iter_many { }}; ($task:ident, $key:ident $input:tt $value_pattern:tt $(if $cond:expr)? => $iter_item:expr) => {{ #[allow(unused_imports)] - use $crate::backend::operation::TaskGuard; + use $crate::backend::storage_schema::TaskStorageAccessors; $task .iter($crate::data::CachedDataItemType::$key) .filter_map(|(key, value)| match (key, value) { @@ -1058,7 +466,7 @@ macro_rules! get_many { macro_rules! update { ($task:ident, $key:ident $input:tt, $update:expr) => {{ #[allow(unused_imports)] - use $crate::backend::operation::TaskGuard; + use $crate::backend::storage_schema::TaskStorageAccessors; #[allow(unused_mut)] let mut update = $update; $task.update($crate::data::CachedDataItemKey::$key $input, |old| { @@ -1161,7 +569,7 @@ macro_rules! update_count_and_get { macro_rules! remove { ($task:ident, $key:ident $input:tt) => {{ #[allow(unused_imports)] - use $crate::backend::operation::TaskGuard; + use $crate::backend::storage_schema::TaskStorageAccessors; if let Some($crate::data::CachedDataItemValue::$key { value }) = $task.remove( &$crate::data::CachedDataItemKey::$key $input ) { @@ -1197,7 +605,7 @@ impl Drop for SnapshotGuard<'_> { } pub struct SnapshotShard<'l, PP, P, PS> { - direct_snapshots: Vec<(TaskId, Box)>, + direct_snapshots: Vec<(TaskId, Box)>, modified: SmallVec<[TaskId; 4]>, storage: &'l Storage, guard: Option>>, @@ -1208,9 +616,9 @@ pub struct SnapshotShard<'l, PP, P, PS> { impl<'l, T, R, PP, P, PS> Iterator for SnapshotShard<'l, PP, P, PS> where - PP: for<'a> Fn(TaskId, &'a InnerStorage) -> T + Sync, + PP: for<'a> Fn(TaskId, &'a TaskStorage) -> T + Sync, P: Fn(TaskId, T) -> R + Sync, - PS: Fn(TaskId, Box) -> R + Sync, + PS: Fn(TaskId, Box) -> R + Sync, { type Item = R; @@ -1220,8 +628,7 @@ where } while let Some(task_id) = self.modified.pop() { let inner = self.storage.map.get(&task_id).unwrap(); - let state = inner.state(); - if !state.any_snapshot() { + if !inner.flags.any_snapshot() { let preprocessed = (self.preprocess)(task_id, &inner); drop(inner); return Some((self.process)(task_id, preprocessed)); @@ -1243,24 +650,3 @@ where None } } - -#[cfg(test)] -mod tests { - use super::*; - - #[test] - fn test_inner_storage_size() { - // InnerStorage size affects memory usage per task. - // We track this to catch unexpected bloat from type changes. - assert_eq!( - std::mem::size_of::(), - 136, - "InnerStorage size changed - please review if this is intentional" - ); - assert_eq!( - std::mem::size_of::(), - 136, - "InnerStorageSnapshot size changed - please review if this is intentional" - ); - } -} diff --git a/turbopack/crates/turbo-tasks-backend/src/backend/storage_schema.rs b/turbopack/crates/turbo-tasks-backend/src/backend/storage_schema.rs index bfd87367c37b86..e6b06810f446b1 100644 --- a/turbopack/crates/turbo-tasks-backend/src/backend/storage_schema.rs +++ b/turbopack/crates/turbo-tasks-backend/src/backend/storage_schema.rs @@ -17,26 +17,22 @@ //! - `data` - Frequently changed bulk data (dependencies, cell data) //! - `meta` - Rarely changed metadata (output, aggregation, flags) //! - `transient` - Not serialized, only exists in memory - -// TODO(PR 2): Remove this once the storage schema is integrated with the rest of the codebase. -// This module is scaffolding for the TaskStorage macro and is not yet used. -#![allow(dead_code)] - use turbo_tasks::{ CellId, SharedReference, TaskId, TraitTypeId, TypedSharedReference, ValueTypeId, task_storage, }; -use crate::data::{ - ActivenessState, AggregationNumber, CellRef, CollectibleRef, CollectiblesRef, Dirtyness, - InProgressCellState, InProgressState, OutputValue, +use crate::{ + backend::counter_map::CounterMap, + data::{ + ActivenessState, AggregationNumber, CellRef, CollectibleRef, CollectiblesRef, Dirtyness, + InProgressCellState, InProgressState, LeafDistance, OutputValue, + }, }; /// Auto-set storage for small sets of keys with unit values. /// Optimized for small collections (< 8 items use SmallVec inline). type AutoSet = auto_hash_map::AutoSet, 1>; -use super::counter_map::CounterMap; - /// Auto-map storage for key-value pairs. type AutoMap = auto_hash_map::AutoMap, 1>; @@ -59,37 +55,92 @@ struct TaskStorageSchema { // ========================================================================= // INLINE FIELDS (hot path, always allocated inline) // ========================================================================= + /// The task's distance for prioritizing invalidation execution + #[field( + storage = "direct", + category = "data", + inline, + default, + variant = "LeafDistance" + )] + pub leaf_distance: LeafDistance, + /// The task's aggregation number for the aggregation tree. /// Uses Default::default() semantics - a zero aggregation number means "not set". - #[field(storage = "direct", category = "meta", inline, default)] + + #[field( + storage = "direct", + category = "meta", + inline, + default, + variant = "AggregationNumber" + )] pub aggregation_number: AggregationNumber, /// Tasks that depend on this task's output. - #[field(storage = "auto_set", category = "data", inline, filter_transient)] + + #[field( + storage = "auto_set", + category = "data", + inline, + filter_transient, + variant = "OutputDependent", + key_field = "task" + )] pub output_dependent: AutoSet, /// The task's output value. /// Filtered during serialization to skip transient outputs (referencing transient tasks). - #[field(storage = "direct", category = "meta", inline, filter_transient)] + #[field( + storage = "direct", + category = "meta", + inline, + filter_transient, + variant = "Output" + )] pub output: Option, /// Upper nodes in the aggregation tree (reference counted). - #[field(storage = "counter_map", category = "meta", inline, filter_transient)] + #[field( + storage = "counter_map", + category = "meta", + inline, + filter_transient, + variant = "Upper", + key_field = "task" + )] pub upper: CounterMap, // ========================================================================= // COLLECTIBLES (meta) // ========================================================================= /// Collectibles emitted by this task (reference counted). - #[field(storage = "counter_map", category = "meta", filter_transient)] + #[field( + storage = "counter_map", + category = "meta", + filter_transient, + variant = "Collectible", + key_field = "collectible" + )] pub collectibles: CounterMap, /// Aggregated collectibles from the subgraph. - #[field(storage = "counter_map", category = "meta", filter_transient)] + #[field( + storage = "counter_map", + category = "meta", + filter_transient, + variant = "AggregatedCollectible", + key_field = "collectible" + )] pub aggregated_collectibles: CounterMap, /// Outdated collectibles to be cleaned up (transient). - #[field(storage = "counter_map", category = "transient")] + #[field( + storage = "counter_map", + category = "transient", + variant = "OutdatedCollectible", + key_field = "collectible" + )] pub outdated_collectibles: CounterMap, // ========================================================================= @@ -98,25 +149,44 @@ struct TaskStorageSchema { // ========================================================================= /// Whether the task is dirty (needs re-execution). /// Absent = clean, present = dirty with the specified Dirtyness state. - #[field(storage = "direct", category = "meta")] + #[field(storage = "direct", category = "meta", variant = "Dirty")] pub dirty: Dirtyness, /// Count of dirty containers in the aggregated subgraph. /// Absent = 0, present = actual count. - #[field(storage = "direct", category = "meta")] + #[field( + storage = "direct", + category = "meta", + variant = "AggregatedDirtyContainerCount" + )] pub aggregated_dirty_container_count: i32, /// Individual dirty containers in the aggregated subgraph. - #[field(storage = "counter_map", category = "meta", filter_transient)] + #[field( + storage = "counter_map", + category = "meta", + filter_transient, + variant = "AggregatedDirtyContainer", + key_field = "task" + )] pub aggregated_dirty_containers: CounterMap, /// Count of clean containers in current session (transient). /// Absent = 0, present = actual count. - #[field(storage = "direct", category = "transient")] + #[field( + storage = "direct", + category = "transient", + variant = "AggregatedCurrentSessionCleanContainerCount" + )] pub aggregated_current_session_clean_container_count: i32, /// Individual clean containers in current session (transient). - #[field(storage = "counter_map", category = "transient")] + #[field( + storage = "counter_map", + category = "transient", + variant = "AggregatedCurrentSessionCleanContainer", + key_field = "task" + )] pub aggregated_current_session_clean_containers: CounterMap, // ========================================================================= @@ -124,15 +194,19 @@ struct TaskStorageSchema { // Persisted flags come first, then transient flags. // ========================================================================= /// Whether the task has an invalidator. - #[field(storage = "flag", category = "meta")] + #[field(storage = "flag", category = "meta", variant = "HasInvalidator")] pub invalidator: bool, /// Whether the task output is immutable (persisted). - #[field(storage = "flag", category = "meta")] + #[field(storage = "flag", category = "meta", variant = "Immutable")] pub immutable: bool, /// Whether clean in current session (transient flag). - #[field(storage = "flag", category = "transient")] + #[field( + storage = "flag", + category = "transient", + variant = "CurrentSessionClean" + )] pub current_session_clean: bool, // ========================================================================= @@ -171,85 +245,156 @@ struct TaskStorageSchema { // CHILDREN & AGGREGATION (meta) // ========================================================================= /// Child tasks of this task. - #[field(storage = "auto_set", category = "meta", filter_transient)] + #[field( + storage = "auto_set", + category = "meta", + filter_transient, + variant = "Child", + key_field = "task" + )] pub children: AutoSet, /// Follower nodes in the aggregation tree (reference counted). - #[field(storage = "counter_map", category = "meta", filter_transient)] + #[field( + storage = "counter_map", + category = "meta", + filter_transient, + variant = "Follower", + key_field = "task" + )] pub followers: CounterMap, // ========================================================================= // DEPENDENCIES (data) // ========================================================================= - /// Tasks whose output this task depends on. - #[field(storage = "auto_set", category = "data", filter_transient)] + #[field( + storage = "auto_set", + category = "data", + filter_transient, + variant = "OutputDependency", + key_field = "target" + )] pub output_dependencies: AutoSet, /// Cells this task depends on. - #[field(storage = "auto_set", category = "data", filter_transient)] - pub cell_dependencies: AutoSet, + #[field( + storage = "auto_set", + category = "data", + filter_transient, + variant = "CellDependency", + key_field = "target, key" + )] + pub cell_dependencies: AutoSet<(CellRef, Option)>, /// Collectibles this task depends on. - #[field(storage = "auto_set", category = "data", filter_transient)] + #[field( + storage = "auto_set", + category = "data", + filter_transient, + variant = "CollectiblesDependency", + key_field = "target" + )] pub collectibles_dependencies: AutoSet, /// Outdated output dependencies to be cleaned up (transient). - #[field(storage = "auto_set", category = "transient")] + #[field( + storage = "auto_set", + category = "transient", + variant = "OutdatedOutputDependency", + key_field = "target" + )] pub outdated_output_dependencies: AutoSet, /// Outdated cell dependencies to be cleaned up (transient). - #[field(storage = "auto_set", category = "transient")] - pub outdated_cell_dependencies: AutoSet, + #[field( + storage = "auto_set", + category = "transient", + variant = "OutdatedCellDependency", + key_field = "target, key" + )] + pub outdated_cell_dependencies: AutoSet<(CellRef, Option)>, /// Outdated collectibles dependencies to be cleaned up (transient). - #[field(storage = "auto_set", category = "transient")] + #[field( + storage = "auto_set", + category = "transient", + variant = "OutdatedCollectiblesDependency", + key_field = "target" + )] pub outdated_collectibles_dependencies: AutoSet, // ========================================================================= // DEPENDENTS - Tasks that depend on this task's cells // ========================================================================= - /// Tasks that depend on specific cells of this task. - /// Maps CellId -> Set - #[field(storage = "auto_set", category = "data", filter_transient)] + #[field( + storage = "auto_set", + category = "data", + variant = "CellDependent", + key_field = "cell, key, task", + filter_transient + )] pub cell_dependents: AutoSet<(CellId, Option, TaskId)>, /// Tasks that depend on collectibles of a specific type from this task. /// Maps TraitTypeId -> Set - #[field(storage = "auto_set", category = "meta", filter_transient)] + + #[field( + storage = "auto_set", + category = "meta", + variant = "CollectiblesDependent", + key_field = "collectible_type, task", + filter_transient + )] pub collectibles_dependents: AutoSet<(TraitTypeId, TaskId)>, // ========================================================================= // CELL DATA (data) // ========================================================================= /// Persistent cell data (serializable). - #[field(storage = "auto_map", category = "data")] + #[field( + storage = "auto_map", + category = "data", + variant = "CellData", + key_field = "cell" + )] pub cell_data: AutoMap, /// Transient cell data (not serializable). - #[field(storage = "auto_map", category = "transient")] + #[field( + storage = "auto_map", + category = "transient", + variant = "TransientCellData", + key_field = "cell" + )] pub transient_cell_data: AutoMap, /// Maximum cell index per cell type. - #[field(storage = "auto_map", category = "data")] + #[field( + storage = "auto_map", + category = "data", + variant = "CellTypeMaxIndex", + key_field = "cell_type" + )] pub cell_type_max_index: AutoMap, // ========================================================================= // TRANSIENT EXECUTION STATE (transient) // ========================================================================= /// Activeness state for root/once tasks (transient). - /// Note: Lazy storage provides natural optionality - - /// presence in Vec = Some, absence = None. No Option wrapper needed. - #[field(storage = "direct", category = "transient")] + #[field(storage = "direct", category = "transient", variant = "Activeness")] pub activeness: ActivenessState, /// In-progress execution state (transient). - /// Note: Lazy storage provides natural optionality - - /// presence in Vec = Some, absence = None. No Option wrapper needed. - #[field(storage = "direct", category = "transient")] + #[field(storage = "direct", category = "transient", variant = "InProgress")] pub in_progress: InProgressState, /// In-progress cell state for cells being computed (transient). - #[field(storage = "auto_map", category = "transient")] + #[field( + storage = "auto_map", + category = "transient", + variant = "InProgressCell", + key_field = "cell" + )] pub in_progress_cells: AutoMap, } @@ -257,7 +402,7 @@ struct TaskStorageSchema { // TaskFlags helper methods (for InnerStorageState compatibility) // ============================================================================= -use crate::backend::TaskDataCategory; +use crate::backend::{TaskDataCategory, storage::SpecificTaskDataCategory}; impl TaskFlags { /// Set restored flags based on category @@ -294,6 +439,38 @@ impl TaskFlags { pub fn any_modified(&self) -> bool { self.meta_modified() || self.data_modified() } + + /// Check if the specified category is modified + pub fn is_modified(&self, category: SpecificTaskDataCategory) -> bool { + match category { + SpecificTaskDataCategory::Meta => self.meta_modified(), + SpecificTaskDataCategory::Data => self.data_modified(), + } + } + + /// Set the modified flag for the specified category + pub fn set_modified(&mut self, category: SpecificTaskDataCategory, value: bool) { + match category { + SpecificTaskDataCategory::Meta => self.set_meta_modified(value), + SpecificTaskDataCategory::Data => self.set_data_modified(value), + } + } + + /// Check if the specified category has a snapshot + pub fn is_snapshot(&self, category: SpecificTaskDataCategory) -> bool { + match category { + SpecificTaskDataCategory::Meta => self.meta_snapshot(), + SpecificTaskDataCategory::Data => self.data_snapshot(), + } + } + + /// Set the snapshot flag for the specified category + pub fn set_snapshot(&mut self, category: SpecificTaskDataCategory, value: bool) { + match category { + SpecificTaskDataCategory::Meta => self.set_meta_snapshot(value), + SpecificTaskDataCategory::Data => self.set_data_snapshot(value), + } + } } // ============================================================================= @@ -388,6 +565,38 @@ impl TaskStorage { None } } + + /// Encode fields for the specified category + pub fn encode( + &self, + category: SpecificTaskDataCategory, + encoder: &mut E, + ) -> Result<(), bincode::error::EncodeError> { + match category { + SpecificTaskDataCategory::Meta => self.encode_meta(encoder), + SpecificTaskDataCategory::Data => self.encode_data(encoder), + } + } + + /// Decode fields for the specified category + pub fn decode( + &mut self, + category: SpecificTaskDataCategory, + decoder: &mut D, + ) -> Result<(), bincode::error::DecodeError> { + match category { + SpecificTaskDataCategory::Meta => self.decode_meta(decoder), + SpecificTaskDataCategory::Data => self.decode_data(decoder), + } + } + + /// Clone only the fields for the specified category + pub fn clone_category_snapshot(&self, category: SpecificTaskDataCategory) -> TaskStorage { + match category { + SpecificTaskDataCategory::Meta => self.clone_meta_snapshot(), + SpecificTaskDataCategory::Data => self.clone_data_snapshot(), + } + } } // Support serialization filtering for CellDependents and CollectibleDependents @@ -406,6 +615,12 @@ impl IsTransient for (CellId, Option, TaskId) { self.2.is_transient() } } +impl IsTransient for (CellRef, Option) { + fn is_transient(&self) -> bool { + self.0.task.is_transient() + } +} + #[cfg(test)] mod tests { use std::mem::size_of; @@ -413,7 +628,38 @@ mod tests { use turbo_tasks::{CellId, TaskId}; use super::*; - use crate::data::{AggregationNumber, CellRef, Dirtyness, OutputValue}; + use crate::{ + backend::storage::SpecificTaskDataCategory, + data::{AggregationNumber, CellRef, Dirtyness, OutputValue}, + }; + + /// Test wrapper that implements TaskStorageAccessors for testing the CachedDataItem adapter. + /// This wrapper doesn't track modifications since we're just testing functionality. + struct TestStorage(TaskStorage); + + impl TestStorage { + fn new() -> Self { + Self(TaskStorage::new()) + } + } + + impl TaskStorageAccessors for TestStorage { + fn typed(&self) -> &TaskStorage { + &self.0 + } + + fn typed_mut(&mut self) -> &mut TaskStorage { + &mut self.0 + } + + fn track_modification(&mut self, _category: SpecificTaskDataCategory) { + // No-op for tests + } + + fn check_access(&self, _category: crate::backend::TaskDataCategory) { + // No-op for tests + } + } #[test] fn test_accessors() { @@ -698,13 +944,16 @@ mod tests { original .output_dependencies_mut() .insert(TaskId::new(200).unwrap()); - original.cell_dependencies_mut().insert(CellRef { - task: TaskId::new(1).unwrap(), - cell: CellId { - type_id: unsafe { turbo_tasks::ValueTypeId::new_unchecked(1) }, - index: 0, + original.cell_dependencies_mut().insert(( + CellRef { + task: TaskId::new(1).unwrap(), + cell: CellId { + type_id: unsafe { turbo_tasks::ValueTypeId::new_unchecked(1) }, + index: 0, + }, }, - }); + None, + )); // Set lazy data transient field (should NOT be serialized) original @@ -815,23 +1064,185 @@ mod tests { #[test] #[cfg(target_pointer_width = "64")] fn test_schema_size() { - // TaskStorage uses lazy storage for most fields, keeping inline storage minimal. - // Current layout (128 bytes): - // - output_dependent (AutoSet): 24 bytes - // - aggregation_number (AggregationNumber with default): 12 bytes - // - output (Option): 32 bytes - // - upper (CounterMap): 24 bytes - // - flags (TaskFlags): 8 bytes - // - lazy (Vec): 24 bytes - // - padding: 4 bytes - // - // Use exact size check to catch regressions in either direction. assert_eq!( size_of::(), - 128, - "TaskStorage size changed! Was 128 bytes, now {} bytes. If this is intentional, \ - update this test.", - size_of::() + 136, + "TaskStorage size changed! If this is intentional, update this test." ); } + + // ========================================================================== + // CachedDataItem Adapter Tests + // ========================================================================== + + #[test] + fn test_adapter_basic() { + use crate::data::{CachedDataItem, CachedDataItemKey, CachedDataItemValue}; + + let mut storage = TestStorage::new(); + let task1 = unsafe { TaskId::new_unchecked(1) }; + let task2 = unsafe { TaskId::new_unchecked(2) }; + + // Test add for inline direct field (Output) + let output_item = CachedDataItem::Output { + value: OutputValue::Output(task1), + }; + assert!(storage.add(output_item.clone())); + assert!(!storage.add(output_item)); // Second add should return false + + // Test get for Output + let key = CachedDataItemKey::Output {}; + assert!(storage.get(&key).is_some()); + assert!(storage.contains_key(&key)); + + // Test remove for Output + let removed = storage.remove(&key); + assert!(matches!(removed, Some(CachedDataItemValue::Output { .. }))); + assert!(storage.get(&key).is_none()); + + // Test add for inline AutoSet field (OutputDependent) + let dep_item = CachedDataItem::OutputDependent { + task: task1, + value: (), + }; + assert!(storage.add(dep_item.clone())); + assert!(!storage.add(dep_item)); // Already exists + + // Verify via typed accessor + assert!(storage.typed().output_dependent().contains(&task1)); + + // Test add another + let dep_item2 = CachedDataItem::OutputDependent { + task: task2, + value: (), + }; + assert!(storage.add(dep_item2)); + assert_eq!(storage.typed().output_dependent().len(), 2); + + // Test remove OutputDependent + let key = CachedDataItemKey::OutputDependent { task: task1 }; + let removed = storage.remove(&key); + assert!(matches!( + removed, + Some(CachedDataItemValue::OutputDependent { value: () }) + )); + assert_eq!(storage.typed().output_dependent().len(), 1); + assert!(!storage.typed().output_dependent().contains(&task1)); + assert!(storage.typed().output_dependent().contains(&task2)); + } + + #[test] + fn test_adapter_flags() { + use crate::data::{CachedDataItem, CachedDataItemKey, CachedDataItemValue}; + + let mut storage = TestStorage::new(); + + // Test flag field (Immutable) + let immutable_item = CachedDataItem::Immutable { value: () }; + assert!(storage.add(immutable_item.clone())); + assert!(storage.typed().flags.immutable()); + assert!(!storage.add(immutable_item)); // Already set + + // Test get for flag + let key = CachedDataItemKey::Immutable {}; + assert!(storage.get(&key).is_some()); + + // Test remove for flag + let removed = storage.remove(&key); + assert!(matches!( + removed, + Some(CachedDataItemValue::Immutable { value: () }) + )); + assert!(!storage.typed().flags.immutable()); + + // Removing again should return None + assert!(storage.remove(&key).is_none()); + } + + #[test] + fn test_adapter_counter_map() { + use crate::data::{CachedDataItem, CachedDataItemKey, CachedDataItemValue}; + + let mut storage = TestStorage::new(); + let task1 = unsafe { TaskId::new_unchecked(1) }; + let task2 = unsafe { TaskId::new_unchecked(2) }; + + // Test inline CounterMap field (Upper) + let upper_item = CachedDataItem::Upper { + task: task1, + value: 5, + }; + assert!(storage.add(upper_item)); + assert_eq!(storage.upper().get(&task1), Some(&5)); + + // Update the value (insert returns old value) + let upper_update = CachedDataItem::Upper { + task: task1, + value: 10, + }; + let old = storage.insert(upper_update); + assert!(matches!(old, Some(CachedDataItemValue::Upper { value: 5 }))); + assert_eq!(storage.upper().get(&task1), Some(&10)); + + // Test lazy CounterMap field (Follower) + let follower_item = CachedDataItem::Follower { + task: task2, + value: 3, + }; + assert!(storage.add(follower_item)); + assert_eq!(storage.followers().unwrap().get(&task2), Some(&3)); + + // Test remove Follower + let key = CachedDataItemKey::Follower { task: task2 }; + let removed = storage.remove(&key); + assert!(matches!( + removed, + Some(CachedDataItemValue::Follower { value: 3 }) + )); + // After removal, followers map might be empty or the key just removed + assert!(storage.followers().is_none_or(|f| f.get(&task2).is_none())); + } + + #[test] + fn test_adapter_lazy_autoset() { + use crate::data::{CachedDataItem, CachedDataItemKey, CachedDataItemValue}; + + let mut storage = TestStorage::new(); + let task1 = unsafe { TaskId::new_unchecked(1) }; + let task2 = unsafe { TaskId::new_unchecked(2) }; + + // Test lazy AutoSet field (Child) + let child_item = CachedDataItem::Child { + task: task1, + value: (), + }; + assert!(storage.add(child_item)); + assert!(storage.children().is_some()); + assert!(storage.children().unwrap().contains(&task1)); + + // Add another child + let child_item2 = CachedDataItem::Child { + task: task2, + value: (), + }; + assert!(storage.add(child_item2)); + assert_eq!(storage.children().unwrap().len(), 2); + + // Test get + let key = CachedDataItemKey::Child { task: task1 }; + assert!(storage.get(&key).is_some()); + let key_missing = CachedDataItemKey::Child { + task: unsafe { TaskId::new_unchecked(999) }, + }; + assert!(storage.get(&key_missing).is_none()); + + // Test remove + let removed = storage.remove(&key); + assert!(matches!( + removed, + Some(CachedDataItemValue::Child { value: () }) + )); + assert_eq!(storage.children().unwrap().len(), 1); + assert!(!storage.children().unwrap().contains(&task1)); + } } diff --git a/turbopack/crates/turbo-tasks-backend/src/backing_storage.rs b/turbopack/crates/turbo-tasks-backend/src/backing_storage.rs index 88fae40857afd7..f448773a77a206 100644 --- a/turbopack/crates/turbo-tasks-backend/src/backing_storage.rs +++ b/turbopack/crates/turbo-tasks-backend/src/backing_storage.rs @@ -6,8 +6,7 @@ use smallvec::SmallVec; use turbo_tasks::{TaskId, backend::CachedTaskType}; use crate::{ - backend::{AnyOperation, TaskDataCategory}, - data::CachedDataItem, + backend::{AnyOperation, SpecificTaskDataCategory, storage_schema::TaskStorage}, utils::chunked_vec::ChunkedVec, }; @@ -44,8 +43,13 @@ pub trait BackingStorageSealed: 'static + Send + Sync { type ReadTransaction<'l>; fn next_free_task_id(&self) -> Result; fn uncompleted_operations(&self) -> Result>; - #[allow(clippy::ptr_arg)] - fn serialize(&self, task: TaskId, data: &Vec) -> Result>; + fn serialize( + &self, + task: TaskId, + data: &TaskStorage, + category: SpecificTaskDataCategory, + ) -> Result>; + fn save_snapshot( &self, operations: Vec>, @@ -78,6 +82,8 @@ pub trait BackingStorageSealed: 'static + Send + Sync { tx: Option<&Self::ReadTransaction<'_>>, task_id: TaskId, ) -> Result>>; + + /// Lookup and decode fields directly into TaskStorage. /// # Safety /// /// `tx` must be a transaction from this BackingStorage instance. @@ -85,8 +91,12 @@ pub trait BackingStorageSealed: 'static + Send + Sync { &self, tx: Option<&Self::ReadTransaction<'_>>, task_id: TaskId, - category: TaskDataCategory, - ) -> Result>; + category: SpecificTaskDataCategory, + storage: &mut TaskStorage, + ) -> Result<()>; + + /// Batch lookup and decode data for multiple tasks directly into TaskStorage instances. + /// Returns a vector of TaskStorage, one for each task_id in the input slice. /// # Safety /// /// `tx` must be a transaction from this BackingStorage instance. @@ -94,16 +104,8 @@ pub trait BackingStorageSealed: 'static + Send + Sync { &self, tx: Option<&Self::ReadTransaction<'_>>, task_ids: &[TaskId], - category: TaskDataCategory, - ) -> Result>> { - let mut results = Vec::with_capacity(task_ids.len()); - for &task_id in task_ids { - // TODO more efficient batch implementation - let data = unsafe { self.lookup_data(tx, task_id, category)? }; - results.push(data); - } - Ok(results) - } + category: SpecificTaskDataCategory, + ) -> Result>; fn shutdown(&self) -> Result<()> { Ok(()) @@ -134,11 +136,14 @@ where fn uncompleted_operations(&self) -> Result> { either::for_both!(self, this => this.uncompleted_operations()) } - - fn serialize(&self, task: TaskId, data: &Vec) -> Result> { - either::for_both!(self, this => this.serialize(task, data)) + fn serialize( + &self, + task: TaskId, + data: &TaskStorage, + category: SpecificTaskDataCategory, + ) -> Result> { + either::for_both!(self, this => this.serialize(task, data, category)) } - fn save_snapshot( &self, operations: Vec>, @@ -207,16 +212,17 @@ where &self, tx: Option<&Self::ReadTransaction<'_>>, task_id: TaskId, - category: TaskDataCategory, - ) -> Result> { + category: SpecificTaskDataCategory, + storage: &mut TaskStorage, + ) -> Result<()> { match self { Either::Left(this) => { let tx = tx.map(|tx| read_transaction_left_or_panic(tx.as_ref())); - unsafe { this.lookup_data(tx, task_id, category) } + unsafe { this.lookup_data(tx, task_id, category, storage) } } Either::Right(this) => { let tx = tx.map(|tx| read_transaction_right_or_panic(tx.as_ref())); - unsafe { this.lookup_data(tx, task_id, category) } + unsafe { this.lookup_data(tx, task_id, category, storage) } } } } @@ -225,8 +231,8 @@ where &self, tx: Option<&Self::ReadTransaction<'_>>, task_ids: &[TaskId], - category: TaskDataCategory, - ) -> Result>> { + category: SpecificTaskDataCategory, + ) -> Result> { match self { Either::Left(this) => { let tx = tx.map(|tx| read_transaction_left_or_panic(tx.as_ref())); diff --git a/turbopack/crates/turbo-tasks-backend/src/data.rs b/turbopack/crates/turbo-tasks-backend/src/data.rs index 8abb16fab3a48a..3f0323f891f11a 100644 --- a/turbopack/crates/turbo-tasks-backend/src/data.rs +++ b/turbopack/crates/turbo-tasks-backend/src/data.rs @@ -7,10 +7,7 @@ use turbo_tasks::{ event::{Event, EventListener}, }; -use crate::{ - backend::TaskDataCategory, - data_storage::{AutoMapStorage, OptionStorage, Storage}, -}; +use crate::backend::TaskDataCategory; // this traits are needed for the transient variants of `CachedDataItem` // transient variants are never cloned or compared @@ -733,6 +730,5 @@ mod tests { assert_eq!(std::mem::size_of::(), 40); assert_eq!(std::mem::size_of::(), 32); assert_eq!(std::mem::size_of::(), 32); - assert_eq!(std::mem::size_of::(), 56); } } diff --git a/turbopack/crates/turbo-tasks-backend/src/data_storage.rs b/turbopack/crates/turbo-tasks-backend/src/data_storage.rs deleted file mode 100644 index 790a74d808e857..00000000000000 --- a/turbopack/crates/turbo-tasks-backend/src/data_storage.rs +++ /dev/null @@ -1,347 +0,0 @@ -use std::hash::{BuildHasherDefault, Hash}; - -use auto_hash_map::{AutoMap, map::Entry}; -use rustc_hash::FxHasher; - -pub trait Storage { - type K; - type V; - type Iterator<'l>: Iterator + 'l - where - Self: 'l; - - /// Adds a key-value pair to the storage, if the key is not already present. - /// Returns `true` if the key was not present and the value was added. - /// Returns `false` if the key was already present. - fn add(&mut self, key: Self::K, value: Self::V) -> bool; - /// Extends the storage with key-value pairs from the iterator. - /// Overwrites existing keys. - /// Returns `true` if all keys were new and added. - /// Returns `false` if any key was already present. - fn extend(&mut self, items: impl Iterator) -> bool; - fn insert(&mut self, key: Self::K, value: Self::V) -> Option; - fn remove(&mut self, key: &Self::K) -> Option; - fn contains_key(&self, key: &Self::K) -> bool; - fn get(&self, key: &Self::K) -> Option<&Self::V>; - fn get_mut(&mut self, key: &Self::K) -> Option<&mut Self::V>; - fn get_mut_or_insert_with(&mut self, key: Self::K, f: impl FnOnce() -> Self::V) - -> &mut Self::V; - fn extract_if<'l, F>(&'l mut self, f: F) -> impl Iterator - where - F: for<'a, 'b> FnMut(&'a Self::K, &'b mut Self::V) -> bool + 'l; - fn update(&mut self, key: Self::K, update: impl FnOnce(Option) -> Option); - fn shrink_to_fit(&mut self); - fn is_empty(&self) -> bool; - fn len(&self) -> usize; - fn iter(&self) -> Self::Iterator<'_>; -} - -fn value_to_key_value(value: &V) -> (&(), &V) { - (&(), value) -} - -#[derive(Debug, Clone)] -pub struct OptionStorage { - value: Option, -} - -impl Default for OptionStorage { - fn default() -> Self { - Self { value: None } - } -} - -impl Storage for OptionStorage { - type K = (); - type V = V; - type Iterator<'l> - = std::option::IntoIter<(&'l (), &'l V)> - where - Self: 'l; - - fn add(&mut self, _: (), value: V) -> bool { - if self.value.is_none() { - self.value = Some(value); - true - } else { - false - } - } - - fn extend(&mut self, items: impl Iterator) -> bool { - let mut added = true; - for (_, value) in items { - added = self.insert((), value).is_none() && added; - } - added - } - - fn insert(&mut self, _: (), value: V) -> Option { - self.value.replace(value) - } - - fn remove(&mut self, _: &()) -> Option { - self.value.take() - } - - fn contains_key(&self, _: &()) -> bool { - self.value.is_some() - } - - fn get(&self, _: &()) -> Option<&V> { - self.value.as_ref() - } - - fn get_mut(&mut self, _: &()) -> Option<&mut V> { - self.value.as_mut() - } - - fn get_mut_or_insert_with(&mut self, _: (), f: impl FnOnce() -> V) -> &mut V { - self.value.get_or_insert_with(f) - } - - fn shrink_to_fit(&mut self) { - // Nothing to do - } - - fn is_empty(&self) -> bool { - self.value.is_none() - } - - fn len(&self) -> usize { - if self.value.is_some() { 1 } else { 0 } - } - - fn iter(&self) -> Self::Iterator<'_> { - self.value.as_ref().map(value_to_key_value).into_iter() - } - - fn extract_if<'l, F>(&'l mut self, mut f: F) -> impl Iterator - where - F: for<'a, 'b> FnMut(&'a Self::K, &'b mut Self::V) -> bool + 'l, - { - if let Some(value) = self.value.as_mut() - && f(&(), value) - { - return self.value.take().map(|v| ((), v)).into_iter(); - } - None.into_iter() - } - - fn update(&mut self, _: (), update: impl FnOnce(Option) -> Option) { - self.value = update(self.value.take()); - } -} - -/// Storage for a single value that uses `Default::default()` to initialize the value "empty". -#[derive(Debug, Clone)] -pub struct DefaultStorage { - value: V, -} - -impl Default for DefaultStorage { - fn default() -> Self { - Self { - value: V::default(), - } - } -} - -impl Storage for DefaultStorage { - type K = (); - type V = V; - type Iterator<'l> - = std::option::IntoIter<(&'l (), &'l V)> - where - Self: 'l; - - fn add(&mut self, _: (), value: V) -> bool { - if self.value == V::default() { - self.value = value; - true - } else { - false - } - } - - fn extend(&mut self, items: impl Iterator) -> bool { - let mut added = true; - for (_, value) in items { - added = self.insert((), value).is_none() && added; - } - added - } - - fn insert(&mut self, _: (), value: V) -> Option { - let old = std::mem::replace(&mut self.value, value); - if old == V::default() { None } else { Some(old) } - } - - fn remove(&mut self, _: &()) -> Option { - let old = std::mem::take(&mut self.value); - if old == V::default() { None } else { Some(old) } - } - - fn contains_key(&self, _: &()) -> bool { - self.value != V::default() - } - - fn get(&self, _: &()) -> Option<&V> { - if self.value != V::default() { - Some(&self.value) - } else { - None - } - } - - fn get_mut(&mut self, _: &()) -> Option<&mut V> { - if self.value != V::default() { - Some(&mut self.value) - } else { - None - } - } - - fn get_mut_or_insert_with(&mut self, _: (), f: impl FnOnce() -> V) -> &mut V { - if self.value == V::default() { - self.value = f(); - } - &mut self.value - } - - fn shrink_to_fit(&mut self) { - // Nothing to do - } - - fn is_empty(&self) -> bool { - self.value == V::default() - } - - fn len(&self) -> usize { - if self.value != V::default() { 1 } else { 0 } - } - - fn iter(&self) -> Self::Iterator<'_> { - if self.value != V::default() { - Some(value_to_key_value(&self.value)).into_iter() - } else { - None.into_iter() - } - } - - fn extract_if<'l, F>(&'l mut self, mut f: F) -> impl Iterator - where - F: for<'a, 'b> FnMut(&'a Self::K, &'b mut Self::V) -> bool + 'l, - { - if self.value != V::default() && f(&(), &mut self.value) { - let old = std::mem::take(&mut self.value); - return Some(((), old)).into_iter(); - } - None.into_iter() - } - - fn update(&mut self, _: (), update: impl FnOnce(Option) -> Option) { - let old = std::mem::take(&mut self.value); - let old_opt = if old == V::default() { None } else { Some(old) }; - self.value = update(old_opt).unwrap_or_default(); - } -} - -#[derive(Debug, Clone)] -pub struct AutoMapStorage { - map: AutoMap, 1>, -} - -impl Default for AutoMapStorage { - fn default() -> Self { - Self { - map: AutoMap::default(), - } - } -} - -impl Storage for AutoMapStorage { - type K = K; - type V = V; - type Iterator<'l> - = auto_hash_map::map::Iter<'l, K, V> - where - Self: 'l; - - fn add(&mut self, key: K, value: V) -> bool { - match self.map.entry(key) { - auto_hash_map::map::Entry::Vacant(entry) => { - entry.insert(value); - true - } - auto_hash_map::map::Entry::Occupied(_) => false, - } - } - - fn extend(&mut self, items: impl Iterator) -> bool { - let len = self.map.len(); - let mut count = 0; - self.map.extend(items.inspect(|_| count += 1)); - self.map.len() == len + count - } - - fn insert(&mut self, key: K, value: V) -> Option { - self.map.insert(key, value) - } - - fn remove(&mut self, key: &K) -> Option { - self.map - .remove(key) - .inspect(|_| self.map.shrink_amortized()) - } - - fn contains_key(&self, key: &K) -> bool { - self.map.contains_key(key) - } - - fn get(&self, key: &K) -> Option<&V> { - self.map.get(key) - } - - fn get_mut(&mut self, key: &K) -> Option<&mut V> { - self.map.get_mut(key) - } - - fn get_mut_or_insert_with(&mut self, key: K, f: impl FnOnce() -> V) -> &mut V { - self.map.entry(key).or_insert_with(f) - } - - fn shrink_to_fit(&mut self) { - self.map.shrink_to_fit() - } - - fn is_empty(&self) -> bool { - self.map.is_empty() - } - - fn len(&self) -> usize { - self.map.len() - } - - fn iter(&self) -> Self::Iterator<'_> { - self.map.iter() - } - - fn extract_if<'l, F>(&'l mut self, f: F) -> impl Iterator - where - F: for<'a, 'b> FnMut(&'a Self::K, &'b mut Self::V) -> bool + 'l, - { - self.map.extract_if(f) - } - - fn update(&mut self, key: K, update: impl FnOnce(Option) -> Option) { - match self.map.entry(key) { - Entry::Vacant(e) => { - if let Some(new) = update(None) { - e.insert(new); - } - } - Entry::Occupied(e) => e.replace_entry_with(move |_, v| update(Some(v))), - } - } -} diff --git a/turbopack/crates/turbo-tasks-backend/src/kv_backing_storage.rs b/turbopack/crates/turbo-tasks-backend/src/kv_backing_storage.rs index c72d15b7d6c86f..4103ade453018b 100644 --- a/turbopack/crates/turbo-tasks-backend/src/kv_backing_storage.rs +++ b/turbopack/crates/turbo-tasks-backend/src/kv_backing_storage.rs @@ -7,7 +7,8 @@ use std::{ use anyhow::{Context, Result}; use turbo_bincode::{ - TurboBincodeBuffer, turbo_bincode_decode, turbo_bincode_encode, turbo_bincode_encode_into, + TurboBincodeBuffer, new_turbo_bincode_decoder, new_turbo_bincode_encoder, turbo_bincode_decode, + turbo_bincode_encode, turbo_bincode_encode_into, }; use turbo_tasks::{ TaskId, @@ -18,9 +19,8 @@ use turbo_tasks::{ use crate::{ GitVersionInfo, - backend::{AnyOperation, TaskDataCategory}, + backend::{AnyOperation, SpecificTaskDataCategory, storage_schema::TaskStorage}, backing_storage::{BackingStorage, BackingStorageSealed}, - data::CachedDataItem, database::{ db_invalidation::{StartupCacheState, check_db_invalidation_and_cleanup, invalidate_db}, db_versioning::handle_db_versioning, @@ -250,8 +250,13 @@ impl BackingStorageSealed get(&self.inner.database).context("Unable to read uncompleted operations from database") } - fn serialize(&self, task: TaskId, data: &Vec) -> Result { - encode_task_data(task, data) + fn serialize( + &self, + task: TaskId, + data: &TaskStorage, + category: SpecificTaskDataCategory, + ) -> Result { + encode_task_data(task, data, category) } fn save_snapshot( @@ -510,64 +515,61 @@ impl BackingStorageSealed &self, tx: Option<&T::ReadTransaction<'_>>, task_id: TaskId, - category: TaskDataCategory, - ) -> Result> { + category: SpecificTaskDataCategory, + storage: &mut TaskStorage, + ) -> Result<()> { let inner = &*self.inner; fn lookup( database: &D, tx: &D::ReadTransaction<'_>, task_id: TaskId, - category: TaskDataCategory, - ) -> Result> { - let Some(bytes) = database.get( - tx, - category_to_key_space(category), - IntKey::new(*task_id).as_ref(), - )? + category: SpecificTaskDataCategory, + storage: &mut TaskStorage, + ) -> Result<()> { + let Some(bytes) = + database.get(tx, category.key_space(), IntKey::new(*task_id).as_ref())? else { - return Ok(Vec::new()); + return Ok(()); }; - let result: Vec = turbo_bincode_decode(bytes.borrow())?; - Ok(result) + let mut decoder = new_turbo_bincode_decoder(bytes.borrow()); + storage + .decode(category, &mut decoder) + .map_err(|e| anyhow::anyhow!("Failed to decode {category:?}: {e:?}")) } inner - .with_tx(tx, |tx| lookup(&inner.database, tx, task_id, category)) - .with_context(|| format!("Looking up data for {task_id} from database failed")) + .with_tx(tx, |tx| { + lookup(&inner.database, tx, task_id, category, storage) + }) + .with_context(|| format!("Looking up task storage for {task_id} from database failed")) } unsafe fn batch_lookup_data( &self, tx: Option<&Self::ReadTransaction<'_>>, task_ids: &[TaskId], - category: TaskDataCategory, - ) -> Result>> { + category: SpecificTaskDataCategory, + ) -> Result> { let inner = &*self.inner; fn lookup( database: &D, tx: &D::ReadTransaction<'_>, task_ids: &[TaskId], - category: TaskDataCategory, - ) -> Result>> { + category: SpecificTaskDataCategory, + ) -> Result> { let int_keys: Vec<_> = task_ids.iter().map(|&id| IntKey::new(*id)).collect(); let keys = int_keys.iter().map(|k| k.as_ref()).collect::>(); - let bytes = database.batch_get( - tx, - match category { - TaskDataCategory::Meta => KeySpace::TaskMeta, - TaskDataCategory::Data => KeySpace::TaskData, - TaskDataCategory::All => unreachable!(), - }, - &keys, - )?; + let bytes = database.batch_get(tx, category.key_space(), &keys)?; bytes .into_iter() .map(|opt_bytes| { + let mut storage = TaskStorage::new(); if let Some(bytes) = opt_bytes { - let result: Vec = turbo_bincode_decode(bytes.borrow())?; - Ok(result) - } else { - Ok(Vec::new()) + let mut decoder = new_turbo_bincode_decoder(bytes.borrow()); + storage + .decode(category, &mut decoder) + .map_err(|e| anyhow::anyhow!("Failed to decode {category:?}: {e:?}"))?; } + Ok(storage) }) .collect::>>() } @@ -575,7 +577,7 @@ impl BackingStorageSealed .with_tx(tx, |tx| lookup(&inner.database, tx, task_ids, category)) .with_context(|| { format!( - "Looking up data for {} tasks from database failed", + "Looking up typed data for {} tasks from database failed", task_ids.len() ) }) @@ -761,55 +763,29 @@ where }) } -fn encode_task_data(task: TaskId, data: &Vec) -> Result { - let orig_result = turbo_bincode_encode(data); - if !cfg!(feature = "verify_serialization") - && let Ok(value) = orig_result - { - return Ok(value); +fn encode_task_data( + task: TaskId, + data: &TaskStorage, + category: SpecificTaskDataCategory, +) -> Result { + // TODO: see if the caller can pass us a buffer instead of us allocating a new one. + // This should be possible and save a lot of small allocations. + let mut buffer = TurboBincodeBuffer::new(); + let mut encoder = new_turbo_bincode_encoder(&mut buffer); + data.encode(category, &mut encoder)?; + + if !cfg!(feature = "verify_serialization") { + return Ok(buffer); } - let mut error = Ok(()); - let mut filtered_data = data.clone(); - filtered_data.retain(|item| match turbo_bincode_encode(&item) { - Ok(buf) => { - if cfg!(feature = "verify_serialization") { - let deserialized = turbo_bincode_decode::(&buf); - if let Err(err) = deserialized { - println!("Data item would not be deserializable {task}: {err:?}\n{item:?}"); - return false; - } - } - true - } - Err(err) => { - if item.is_optional() { - if cfg!(feature = "verify_serialization") { - println!( - "Skipping non-encodable optional item for {task}: {item:?} due to {err}" - ); - } - } else { - error = - Err(err).context(format!("Unable to encode data item for {task}: {item:?}")); - } - false - } - }); - error?; - - (if filtered_data.len() == data.len() { - orig_result - } else { - turbo_bincode_encode(&filtered_data) - }) - .with_context(|| format!("Unable to serialize data items for {task}: {filtered_data:#?}")) -} + TaskStorage::new() + .decode(category, &mut new_turbo_bincode_decoder(buffer.borrow())) + .with_context(|| { + format!( + "expected to be able to decode serialized data for '{category:?}' information for \ + {task}" + ) + })?; -fn category_to_key_space(category: TaskDataCategory) -> KeySpace { - match category { - TaskDataCategory::Meta => KeySpace::TaskMeta, - TaskDataCategory::Data => KeySpace::TaskData, - TaskDataCategory::All => unreachable!(), - } + Ok(buffer) } diff --git a/turbopack/crates/turbo-tasks-backend/src/lib.rs b/turbopack/crates/turbo-tasks-backend/src/lib.rs index 6d1ad48a488d0b..417449a840c5be 100644 --- a/turbopack/crates/turbo-tasks-backend/src/lib.rs +++ b/turbopack/crates/turbo-tasks-backend/src/lib.rs @@ -6,7 +6,6 @@ mod backend; mod backing_storage; mod data; -mod data_storage; mod database; mod kv_backing_storage; mod utils; diff --git a/turbopack/crates/turbo-tasks-fetch/Cargo.toml b/turbopack/crates/turbo-tasks-fetch/Cargo.toml index 3184cb72b6ae7c..177972f672af4f 100644 --- a/turbopack/crates/turbo-tasks-fetch/Cargo.toml +++ b/turbopack/crates/turbo-tasks-fetch/Cargo.toml @@ -46,6 +46,16 @@ reqwest = { workspace = true, features = ["rustls"] } reqwest = { workspace = true, features = ["rustls-no-provider"] } rustls = { version = "0.23", default-features = false, features = ["ring", "std", "tls12"] } +# On Linux, we need to add webpki-roots, in case the user is building a bare-bones docker image that +# does not contain any root certs (e.g. `oven/bun:slim`). See footnote #2 here: +# https://github.com/rustls/rustls-platform-verifier/tree/93f729c6309680486d33f982e3ba3c42b976f774?tab=readme-ov-file#user-content-fn-3-7402e7116652999a2e8c2860b94080eb +# +# It would be more ideal to use the smaller `webpki-roots` crate instead of `webpki-root-certs`, but +# API limitations of reqwest require us to get the full certificate: +# https://github.com/seanmonstar/reqwest/discussions/2906#discussioncomment-15483148 +[target.'cfg(target_os = "linux")'.dependencies] +webpki-root-certs = "1" + # On Windows ARM64, use native-tls because rustls with ring has build issues. [target.'cfg(all(windows, target_arch = "aarch64"))'.dependencies] reqwest = { workspace = true, features = ["native-tls"] } diff --git a/turbopack/crates/turbo-tasks-fetch/src/client.rs b/turbopack/crates/turbo-tasks-fetch/src/client.rs index e77d722cec7079..6dafa4099ffe60 100644 --- a/turbopack/crates/turbo-tasks-fetch/src/client.rs +++ b/turbopack/crates/turbo-tasks-fetch/src/client.rs @@ -62,6 +62,18 @@ impl FetchClientConfig { { builder = builder.tls_backend_native(); } + #[cfg(target_os = "linux")] + { + // Add webpki_root_certs on Linux (in addition to reqwest's default + // `rustls-platform-verifier`), in case the user is building in a bare-bones docker + // image that does not contain any root certs (e.g. `oven/bun:slim`). + builder = builder.tls_certs_merge(webpki_root_certs::TLS_SERVER_ROOT_CERTS.iter().map( + |der| { + reqwest::Certificate::from_der(der) + .expect("webpki_root_certs should parse correctly") + }, + )) + } builder.build() } } diff --git a/turbopack/crates/turbo-tasks-fs/Cargo.toml b/turbopack/crates/turbo-tasks-fs/Cargo.toml index 57477aa9f4028d..d9699c19a97289 100644 --- a/turbopack/crates/turbo-tasks-fs/Cargo.toml +++ b/turbopack/crates/turbo-tasks-fs/Cargo.toml @@ -43,6 +43,7 @@ rustc-hash = { workspace = true } serde = { workspace = true, features = ["rc"] } serde_json = { workspace = true } serde_path_to_error = { workspace = true } +thiserror = { workspace = true } tokio = { workspace = true } tracing = { workspace = true } triomphe = { workspace = true } @@ -55,6 +56,7 @@ urlencoding = { workspace = true } [dev-dependencies] criterion = { workspace = true, features = ["async_tokio"] } +rand = { workspace = true } rstest = { workspace = true } sha2 = "0.10.2" tempfile = { workspace = true } diff --git a/turbopack/crates/turbo-tasks-fs/src/lib.rs b/turbopack/crates/turbo-tasks-fs/src/lib.rs index 308012054c5add..5567e1514573a5 100644 --- a/turbopack/crates/turbo-tasks-fs/src/lib.rs +++ b/turbopack/crates/turbo-tasks-fs/src/lib.rs @@ -39,7 +39,7 @@ use std::{ fmt::{self, Debug, Display, Formatter}, fs::FileType, future::Future, - io::{self, BufRead, BufReader, ErrorKind, Read}, + io::{self, BufRead, BufReader, ErrorKind, Read, Write as _}, mem::take, path::{MAIN_SEPARATOR, Path, PathBuf}, sync::{Arc, LazyLock, Weak}, @@ -80,7 +80,7 @@ use crate::{ json::UnparsableJson, mutex_map::MutexMap, read_glob::{read_glob, track_glob}, - retry::retry_blocking, + retry::{can_retry, retry_blocking, retry_blocking_custom}, rope::{Rope, RopeReader}, util::extract_disk_access, watcher::DiskWatcher, @@ -127,61 +127,56 @@ pub const MAX_SAFE_FILE_NAME_LENGTH: usize = 200; pub fn validate_path_length(path: &Path) -> Result> { /// Here we check if the path is too long for windows, and if so, attempt to canonicalize it /// to a UNC path. - #[cfg(windows)] fn validate_path_length_inner(path: &Path) -> Result> { - const MAX_PATH_LENGTH_WINDOWS: usize = 260; - const UNC_PREFIX: &str = "\\\\?\\"; + if cfg!(windows) { + const MAX_PATH_LENGTH_WINDOWS: usize = 260; + const UNC_PREFIX: &str = "\\\\?\\"; - if path.starts_with(UNC_PREFIX) { - return Ok(path.into()); - } + if path.starts_with(UNC_PREFIX) { + return Ok(path.into()); + } - if path.as_os_str().len() > MAX_PATH_LENGTH_WINDOWS { - let new_path = std::fs::canonicalize(path) - .map_err(|_| anyhow!("file is too long, and could not be normalized"))?; - return Ok(new_path.into()); - } + if path.as_os_str().len() > MAX_PATH_LENGTH_WINDOWS { + let new_path = std::fs::canonicalize(path).map_err(|err| { + anyhow!(err).context("file is too long, and could not be normalized") + })?; + return Ok(new_path.into()); + } - Ok(path.into()) - } + Ok(path.into()) + } else { + /// here we are only going to check if the total length exceeds, or the last segment + /// exceeds. This heuristic is primarily to avoid long file names, and it makes the + /// operation much cheaper. + const MAX_FILE_NAME_LENGTH_UNIX: usize = 255; + // macOS reports a limit of 1024, but I (@arlyon) have had issues with paths above 1016 + // so we subtract a bit to be safe. on most linux distros this is likely a lot larger + // than 1024, but macOS is *special* + const MAX_PATH_LENGTH: usize = 1024 - 8; + + // check the last segment (file name) + if path + .file_name() + .map(|n| n.as_encoded_bytes().len()) + .unwrap_or(0) + > MAX_FILE_NAME_LENGTH_UNIX + { + anyhow::bail!( + "file name is too long (exceeds {} bytes)", + MAX_FILE_NAME_LENGTH_UNIX, + ); + } - /// Here we are only going to check if the total length exceeds, or the last segment exceeds. - /// This heuristic is primarily to avoid long file names, and it makes the operation much - /// cheaper. - #[cfg(not(windows))] - fn validate_path_length_inner(path: &Path) -> Result> { - const MAX_FILE_NAME_LENGTH_UNIX: usize = 255; - // macOS reports a limit of 1024, but I (@arlyon) have had issues with paths above 1016 - // so we subtract a bit to be safe. on most linux distros this is likely a lot larger than - // 1024, but macOS is *special* - const MAX_PATH_LENGTH: usize = 1024 - 8; - - // check the last segment (file name) - if path - .file_name() - .map(|n| n.as_encoded_bytes().len()) - .unwrap_or(0) - > MAX_FILE_NAME_LENGTH_UNIX - { - anyhow::bail!( - "file name is too long (exceeds {} bytes)", - MAX_FILE_NAME_LENGTH_UNIX - ); - } + if path.as_os_str().len() > MAX_PATH_LENGTH { + anyhow::bail!("path is too long (exceeds {MAX_PATH_LENGTH} bytes)"); + } - if path.as_os_str().len() > MAX_PATH_LENGTH { - anyhow::bail!("path is too long (exceeds {} bytes)", MAX_PATH_LENGTH); + Ok(path.into()) } - - Ok(path.into()) } - validate_path_length_inner(path).with_context(|| { - format!( - "path length for file {} exceeds max length of filesystem", - path.to_string_lossy() - ) - }) + validate_path_length_inner(path) + .with_context(|| format!("path length for file {path:?} exceeds max length of filesystem")) } trait ConcurrencyLimitedExt { @@ -469,15 +464,10 @@ impl DiskFileSystemInner { let root_path = self.root_path().to_path_buf(); // create the directory for the filesystem on disk, if it doesn't exist - retry_blocking(root_path.clone(), move |path| { - let _tracing = - tracing::info_span!("create root directory", name = display(path.display())) - .entered(); - - std::fs::create_dir_all(path) - }) - .concurrency_limited(&self.write_semaphore) - .await?; + retry_blocking(|| std::fs::create_dir_all(&root_path)) + .instrument(tracing::info_span!("create root directory", name = ?root_path)) + .concurrency_limited(&self.write_semaphore) + .await?; self.watcher .start_watching(self.clone(), report_invalidation_reason, poll_interval)?; @@ -491,12 +481,8 @@ impl DiskFileSystemInner { |fs_context| fs_context.created_directories.contains(directory), ); if !already_created { - let func = |p: &Path| std::fs::create_dir_all(p); - retry_blocking(directory.to_path_buf(), func) - .instrument(tracing::info_span!( - "create directory", - name = display(directory.display()) - )) + retry_blocking(|| std::fs::create_dir_all(directory)) + .instrument(tracing::info_span!("create directory", name = ?directory)) .concurrency_limited(&self.write_semaphore) .await?; ApplyEffectsContext::with(|fs_context: &mut DiskFileSystemApplyContext| { @@ -707,11 +693,8 @@ impl FileSystem for DiskFileSystem { self.inner.register_read_invalidator(&full_path)?; let _lock = self.inner.lock_path(&full_path).await; - let content = match retry_blocking(full_path.clone(), |path: &Path| File::from_path(path)) - .instrument(tracing::info_span!( - "read file", - name = display(full_path.display()) - )) + let content = match retry_blocking(|| File::from_path(&full_path)) + .instrument(tracing::info_span!("read file", name = ?full_path)) .concurrency_limited(&self.inner.read_semaphore) .await { @@ -719,9 +702,7 @@ impl FileSystem for DiskFileSystem { Err(e) if e.kind() == ErrorKind::NotFound || e.kind() == ErrorKind::InvalidFilename => { FileContent::NotFound } - Err(e) => { - bail!(anyhow!(e).context(format!("reading file {}", full_path.display()))) - } + Err(e) => return Err(anyhow!(e).context(format!("reading file {full_path:?}"))), }; Ok(content.cell()) } @@ -738,15 +719,11 @@ impl FileSystem for DiskFileSystem { self.inner.register_dir_invalidator(&full_path)?; - // we use the sync std function here as it's a lot faster (600%) in - // node-file-trace - let read_dir = match retry_blocking(full_path.clone(), |path| { - let _span = - tracing::info_span!("read directory", name = display(path.display())).entered(); - std::fs::read_dir(path) - }) - .concurrency_limited(&self.inner.read_semaphore) - .await + // we use the sync std function here as it's a lot faster (600%) in node-file-trace + let read_dir = match retry_blocking(|| std::fs::read_dir(&full_path)) + .instrument(tracing::info_span!("read directory", name = ?full_path)) + .concurrency_limited(&self.inner.read_semaphore) + .await { Ok(dir) => dir, Err(e) @@ -757,7 +734,7 @@ impl FileSystem for DiskFileSystem { return Ok(RawDirectoryContent::not_found()); } Err(e) => { - bail!(anyhow!(e).context(format!("reading dir {}", full_path.display()))) + return Err(anyhow!(e).context(format!("reading dir {full_path:?}"))); } }; let dir_path = fs_path.path.as_str(); @@ -797,7 +774,7 @@ impl FileSystem for DiskFileSystem { }; // we filter out any non unicode names - let file_name: RcStr = e.file_name().to_str()?.into(); + let file_name = RcStr::from(e.file_name().to_str()?); // Filter out denied entries if denied_entries.contains(file_name.as_str()) { return None; @@ -814,7 +791,7 @@ impl FileSystem for DiskFileSystem { Some(anyhow::Ok((file_name, entry))) }) .collect::>() - .with_context(|| format!("reading directory item in {}", full_path.display()))?; + .with_context(|| format!("reading directory item in {full_path:?}"))?; Ok(RawDirectoryContent::new(entries)) } @@ -832,18 +809,14 @@ impl FileSystem for DiskFileSystem { self.inner.register_read_invalidator(&full_path)?; let _lock = self.inner.lock_path(&full_path).await; - let link_path = - match retry_blocking(full_path.clone(), |path: &Path| std::fs::read_link(path)) - .instrument(tracing::info_span!( - "read symlink", - name = display(full_path.display()) - )) - .concurrency_limited(&self.inner.read_semaphore) - .await - { - Ok(res) => res, - Err(_) => return Ok(LinkContent::NotFound.cell()), - }; + let link_path = match retry_blocking(|| std::fs::read_link(&full_path)) + .instrument(tracing::info_span!("read symlink", name = ?full_path)) + .concurrency_limited(&self.inner.read_semaphore) + .await + { + Ok(res) => res, + Err(_) => return Ok(LinkContent::NotFound.cell()), + }; let is_link_absolute = link_path.is_absolute(); let mut file = link_path.clone(); @@ -880,7 +853,7 @@ impl FileSystem for DiskFileSystem { }; let (target, file_type) = if is_link_absolute { - let target_string: RcStr = relative_to_root_path.to_string_lossy().into(); + let target_string = RcStr::from(relative_to_root_path.to_string_lossy()); ( target_string.clone(), FileSystemPath::new_normalized(fs_path.fs().to_resolved().await?, target_string) @@ -889,7 +862,7 @@ impl FileSystem for DiskFileSystem { ) } else { let link_path_string_cow = link_path.to_string_lossy(); - let link_path_unix: RcStr = sys_to_unix(&link_path_string_cow).into(); + let link_path_unix = RcStr::from(sys_to_unix(&link_path_string_cow)); ( link_path_unix.clone(), fs_path.parent().join(&link_path_unix)?.get_type().await?, @@ -956,10 +929,7 @@ impl FileSystem for DiskFileSystem { // not wasting cycles. let compare = content .streaming_compare(&full_path) - .instrument(tracing::info_span!( - "read file before write", - name = display(full_path.display()) - )) + .instrument(tracing::info_span!("read file before write", name = ?full_path)) .concurrency_limited(&inner.read_semaphore) .await?; if compare == FileComparison::Equal { @@ -981,19 +951,14 @@ impl FileSystem for DiskFileSystem { if create_directory && let Some(parent) = full_path.parent() { inner.create_directory(parent).await.with_context(|| { format!( - "failed to create directory {} for write to {}", - parent.display(), - full_path.display() + "failed to create directory {parent:?} for write to {full_path:?}", ) })?; } - let full_path_to_write = full_path.clone(); let content = content.clone(); - retry_blocking(full_path_to_write.into_owned(), move |full_path| { - use std::io::Write; - - let mut f = std::fs::File::create(full_path)?; + retry_blocking(|| { + let mut f = std::fs::File::create(&full_path)?; let FileContent::Content(file) = &*content else { unreachable!() }; @@ -1007,7 +972,7 @@ impl FileSystem for DiskFileSystem { .is_some_and(|v| v == "1" || v == "true") }); if *WRITE_VERSION { - let mut full_path = full_path.to_owned(); + let mut full_path = full_path.clone().into_owned(); let hash = hash_xxh3_hash64(file); let ext = full_path.extension(); let ext = if let Some(ext) = ext { @@ -1024,32 +989,24 @@ impl FileSystem for DiskFileSystem { } Ok::<(), io::Error>(()) }) - .instrument(tracing::info_span!( - "write file", - name = display(full_path.display()) - )) + .instrument(tracing::info_span!("write file", name = ?full_path)) .concurrency_limited(&inner.write_semaphore) .await - .with_context(|| format!("failed to write to {}", full_path.display()))?; + .with_context(|| format!("failed to write to {full_path:?}"))?; } FileContent::NotFound => { - retry_blocking(full_path.clone().into_owned(), |path| { - std::fs::remove_file(path) - }) - .instrument(tracing::info_span!( - "remove file", - name = display(full_path.display()) - )) - .concurrency_limited(&inner.write_semaphore) - .await - .or_else(|err| { - if err.kind() == ErrorKind::NotFound { - Ok(()) - } else { - Err(err) - } - }) - .with_context(|| format!("removing {} failed", full_path.display()))?; + retry_blocking(|| std::fs::remove_file(&full_path)) + .instrument(tracing::info_span!("remove file", name = ?full_path)) + .concurrency_limited(&inner.write_semaphore) + .await + .or_else(|err| { + if err.kind() == ErrorKind::NotFound { + Ok(()) + } else { + Err(err) + } + }) + .with_context(|| format!("removing {full_path:?} failed"))?; } } @@ -1134,17 +1091,10 @@ impl FileSystem for DiskFileSystem { LinkContent::NotFound => OsSpecificLinkContent::NotFound, }; - // TODO(sokra) perform a untracked read here, register an invalidator and get - // all existing invalidators - let old_content = match retry_blocking(full_path.clone().into_owned(), |path| { - std::fs::read_link(path) - }) - .instrument(tracing::info_span!( - "read symlink before write", - name = display(full_path.display()) - )) - .concurrency_limited(&inner.read_semaphore) - .await + let old_content = match retry_blocking(|| std::fs::read_link(&full_path)) + .instrument(tracing::info_span!("read symlink before write", name = ?full_path)) + .concurrency_limited(&inner.read_semaphore) + .await { Ok(res) => Some((res.is_absolute(), res)), Err(_) => None, @@ -1183,81 +1133,97 @@ impl FileSystem for DiskFileSystem { if create_directory && let Some(parent) = full_path.parent() { inner.create_directory(parent).await.with_context(|| { format!( - "failed to create directory {} for write link to {}", - parent.display(), - full_path.display() + "failed to create directory {parent:?} for write link to \ + {full_path:?}", ) })?; } - if old_content.is_some() { - // Remove existing symlink before creating a new one. On Unix, symlink(2) - // fails with EEXIST if the link already exists instead of overwriting it. - // Windows has similar behavior with junction points. - remove_symbolic_link_dir_helper(&full_path) - .instrument(tracing::info_span!( - "remove existing symlink before write", - name = display(full_path.display()) - )) - .concurrency_limited(&inner.write_semaphore) - .await - .with_context(|| { - format!("removing existing symlink {} failed", full_path.display()) - })?; + #[derive(thiserror::Error, Debug)] + #[error("{msg}: {source}")] + struct SymlinkCreationError { + msg: &'static str, + #[source] + source: io::Error, } - let span = - tracing::info_span!("create symlink", name = display(full_path.display())); - retry_blocking(target.clone(), move |target_path| { - let _span = tracing::info_span!( - "write symlink", - name = display(target_path.display()) - ) - .entered(); - #[cfg(not(windows))] - { - std::os::unix::fs::symlink(target_path, &full_path) + let mut has_old_content = old_content.is_some(); + let try_create_link = || { + if has_old_content { + // Remove existing symlink before creating a new one. On Unix, + // symlink(2) fails with EEXIST if the link already exists instead of + // overwriting it. Windows has similar behavior with junction points. + remove_symbolic_link_dir_helper(&full_path).map_err(|err| { + SymlinkCreationError { + msg: "removal of existing symbolic link or junction point \ + failed", + source: err, + } + })?; + has_old_content = false; } + #[cfg(not(windows))] + let io_result = std::os::unix::fs::symlink(&target, &full_path); #[cfg(windows)] - { - if is_directory { - std::os::windows::fs::junction_point(target_path, &full_path) - } else { - std::os::windows::fs::symlink_file(target_path, &full_path) + let io_result = if is_directory { + std::os::windows::fs::junction_point(&target, &full_path) + } else { + std::os::windows::fs::symlink_file(&target, &full_path) + }; + io_result.map_err(|err| { + if err.kind() == ErrorKind::AlreadyExists { + // try to remove the symlink on the next iteration of the loop + has_old_content = true; } - } - }) - .instrument(span) - .concurrency_limited(&inner.write_semaphore) - .await - .with_context(|| { + SymlinkCreationError { + msg: "creation of a new symbolic link or junction point failed", + source: err, + } + }) + }; + fn can_retry_link(err: &SymlinkCreationError) -> bool { + err.source.kind() == ErrorKind::AlreadyExists || can_retry(&err.source) + } + let err_context = || { #[cfg(not(windows))] - let message = format!("failed to create symlink to {}", target.display()); + let message = format!( + "failed to create symlink at {full_path:?} pointing to {target:?}" + ); #[cfg(windows)] let message = if is_directory { - format!("failed to create junction point to {}", target.display()) + format!( + "failed to create junction point at {full_path:?} pointing to \ + {target:?}" + ) } else { format!( - "failed to create symlink to {}\n\ - (Note: creating file symlinks on Windows require developer mode or admin permissions: https://learn.microsoft.com/en-us/windows/advanced-settings/developer-mode)", - target.display() + "failed to create symlink at {full_path:?} pointing to {target:?}\n\ + (Note: creating file symlinks on Windows require developer mode or \ + admin permissions: \ + https://learn.microsoft.com/en-us/windows/advanced-settings/developer-mode)", ) }; message - })?; + }; + retry_blocking_custom(try_create_link, can_retry_link) + .instrument(tracing::info_span!( + "write symlink", + name = ?full_path, + target = ?target, + )) + .concurrency_limited(&inner.write_semaphore) + .await + .with_context(err_context)?; } OsSpecificLinkContent::Invalid => { - bail!("invalid symlink target: {}", full_path.display()) + bail!("invalid symlink target: {full_path:?}") } OsSpecificLinkContent::NotFound => { - remove_symbolic_link_dir_helper(&full_path) - .instrument(tracing::info_span!( - "remove symlink", - name = display(full_path.display()) - )) + retry_blocking(|| remove_symbolic_link_dir_helper(&full_path)) + .instrument(tracing::info_span!("remove symlink", name = ?full_path)) .concurrency_limited(&inner.write_semaphore) .await - .with_context(|| format!("removing {} failed", full_path.display()))?; + .with_context(|| format!("removing {full_path:?} failed"))?; } } @@ -1282,55 +1248,45 @@ impl FileSystem for DiskFileSystem { self.inner.register_read_invalidator(&full_path)?; let _lock = self.inner.lock_path(&full_path).await; - let meta = retry_blocking(full_path.clone(), |path| std::fs::metadata(path)) - .instrument(tracing::info_span!( - "read metadata", - name = display(full_path.display()) - )) + let meta = retry_blocking(|| std::fs::metadata(&full_path)) + .instrument(tracing::info_span!("read metadata", name = ?full_path)) .concurrency_limited(&self.inner.read_semaphore) .await - .with_context(|| format!("reading metadata for {}", full_path.display()))?; + .with_context(|| format!("reading metadata for {:?}", full_path))?; Ok(FileMeta::cell(meta.into())) } } -async fn remove_symbolic_link_dir_helper(path: impl AsRef) -> Result<()> { - let path = path.as_ref(); - retry_blocking(path.to_owned(), move |path| { - if cfg!(windows) { - // Junction points on Windows are treated as directories, and therefore need - // `remove_dir`: - // - // > `RemoveDirectory` can be used to remove a directory junction. Since the target - // > directory and its contents will remain accessible through its canonical path, the - // > target directory itself is not affected by removing a junction which targets it. - // - // -- https://learn.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-removedirectoryw - // - // However, Next 16.1.0 shipped with symlinks, before we switched to junction links on - // Windows, and `remove_dir` won't work on symlinks. So try to remove it as a directory - // (junction) first, and then fall back to removing it as a file (symlink). - std::fs::remove_dir(path).or_else(|err| { - if err.kind() == ErrorKind::NotADirectory { - std::fs::remove_file(path) - } else { - Err(err) - } - }) - } else { - std::fs::remove_file(path) - } - }) - .await - .or_else(|err| { - if err.kind() == ErrorKind::NotFound { - Ok(()) - } else { - Err(err) - } - }) - .with_context(|| format!("removing existing symlink {path:?} failed")) +fn remove_symbolic_link_dir_helper(path: &Path) -> io::Result<()> { + let result = if cfg!(windows) { + // Junction points on Windows are treated as directories, and therefore need + // `remove_dir`: + // + // > `RemoveDirectory` can be used to remove a directory junction. Since the target + // > directory and its contents will remain accessible through its canonical path, the + // > target directory itself is not affected by removing a junction which targets it. + // + // -- https://learn.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-removedirectoryw + // + // However, Next 16.1.0 shipped with symlinks, before we switched to junction links on + // Windows, and `remove_dir` won't work on symlinks. So try to remove it as a directory + // (junction) first, and then fall back to removing it as a file (symlink). + std::fs::remove_dir(path).or_else(|err| { + if err.kind() == ErrorKind::NotADirectory { + std::fs::remove_file(path) + } else { + Err(err) + } + }) + } else { + std::fs::remove_file(path) + }; + match result { + Ok(()) => Ok(()), + Err(err) if err.kind() == ErrorKind::NotFound => Ok(()), + Err(err) => Err(err), + } } #[turbo_tasks::value_impl] @@ -1531,7 +1487,7 @@ impl FileSystemPath { bail!( "FileSystemPath(\"{}\").join(\"{}\") leaves the filesystem root", self.path, - path + path, ); } } @@ -1542,7 +1498,7 @@ impl FileSystemPath { bail!( "FileSystemPath(\"{}\").append(\"{}\") must not append '/'", self.path, - path + path, ) } Ok(Self::new_normalized( @@ -1558,7 +1514,7 @@ impl FileSystemPath { bail!( "FileSystemPath(\"{}\").append_to_stem(\"{}\") must not append '/'", self.path, - appending + appending, ) } if let (path, Some(ext)) = self.split_extension() { @@ -1925,10 +1881,8 @@ impl FileContent { /// Performs a comparison of self's data against a disk file's streamed /// read. async fn streaming_compare(&self, path: &Path) -> Result { - let old_file = extract_disk_access( - retry_blocking(path.to_path_buf(), |path| std::fs::File::open(path)).await, - path, - )?; + let old_file = + extract_disk_access(retry_blocking(|| std::fs::File::open(path)).await, path)?; let Some(old_file) = old_file else { return Ok(match self { FileContent::NotFound => FileComparison::Equal, @@ -1940,14 +1894,7 @@ impl FileContent { return Ok(FileComparison::NotEqual); }; - let old_meta = extract_disk_access( - retry_blocking(path.to_path_buf(), { - let file_for_metadata = old_file.try_clone()?; - move |_| file_for_metadata.metadata() - }) - .await, - path, - )?; + let old_meta = extract_disk_access(retry_blocking(|| old_file.metadata()).await, path)?; let Some(old_meta) = old_meta else { // If we failed to get meta, then the old file has been deleted between the // handle open. In which case, we just pretend the file never @@ -2987,8 +2934,9 @@ mod tests { io::Write, }; + use rand::{Rng, SeedableRng}; use turbo_rcstr::{RcStr, rcstr}; - use turbo_tasks::{ResolvedVc, apply_effects}; + use turbo_tasks::{ResolvedVc, Vc, apply_effects}; use turbo_tasks_backend::{BackendOptions, TurboTasksBackend, noop_backing_storage}; use crate::{DiskFileSystem, FileSystem, FileSystemPath, LinkContent, LinkType}; @@ -3085,6 +3033,111 @@ mod tests { .await .unwrap(); } + + const STRESS_ITERATIONS: usize = 100; + const STRESS_PARALLELISM: usize = 8; + const STRESS_TARGET_COUNT: usize = 20; + const STRESS_SYMLINK_COUNT: usize = 16; + + #[turbo_tasks::function(operation)] + fn disk_file_system_operation(fs_root: RcStr) -> Vc { + DiskFileSystem::new(rcstr!("test"), fs_root) + } + + #[turbo_tasks::function(operation)] + fn disk_file_system_root_operation(fs: ResolvedVc) -> Vc { + fs.root() + } + + #[turbo_tasks::function(operation)] + async fn write_symlink_stress_batch( + fs: ResolvedVc, + symlinks_dir: FileSystemPath, + updates: Vec<(usize, usize)>, + ) -> anyhow::Result<()> { + use turbo_tasks::TryJoinIterExt; + + updates + .into_iter() + .map(|(symlink_idx, target_idx)| { + let target = RcStr::from(format!("../_targets/{target_idx}")); + let symlink_path = symlinks_dir.join(&symlink_idx.to_string()).unwrap(); + async move { + fs.write_link( + symlink_path, + LinkContent::Link { + target, + link_type: LinkType::DIRECTORY, + } + .cell(), + ) + .await + } + }) + .try_join() + .await?; + Ok(()) + } + + #[tokio::test(flavor = "multi_thread", worker_threads = 2)] + async fn test_symlink_stress() { + let scratch = tempfile::tempdir().unwrap(); + let path = scratch.path().to_owned(); + + let targets_dir = path.join("_targets"); + create_dir_all(&targets_dir).unwrap(); + for i in 0..STRESS_TARGET_COUNT { + create_dir_all(targets_dir.join(i.to_string())).unwrap(); + } + create_dir_all(path.join("_symlinks")).unwrap(); + + let root = RcStr::from(path.to_str().unwrap()); + + let tt = turbo_tasks::TurboTasks::new(TurboTasksBackend::new( + BackendOptions::default(), + noop_backing_storage(), + )); + + tt.run_once(async move { + let fs = disk_file_system_operation(root) + .resolve_strongly_consistent() + .await?; + let root_path = disk_file_system_root_operation(fs) + .resolve_strongly_consistent() + .await? + .owned() + .await?; + let symlinks_dir = root_path.join("_symlinks")?; + + let initial_updates: Vec<(usize, usize)> = + (0..STRESS_SYMLINK_COUNT).map(|i| (i, 0)).collect(); + let initial_op = + write_symlink_stress_batch(fs, symlinks_dir.clone(), initial_updates); + initial_op.read_strongly_consistent().await?; + apply_effects(initial_op).await?; + + let mut rng = rand::rngs::SmallRng::seed_from_u64(0); + for _ in 0..STRESS_ITERATIONS { + let updates: Vec<(usize, usize)> = (0..STRESS_PARALLELISM) + .map(|_| { + let symlink_idx = rng.random_range(0..STRESS_SYMLINK_COUNT); + let target_idx = rng.random_range(0..STRESS_TARGET_COUNT); + (symlink_idx, target_idx) + }) + .collect(); + + let write_op = write_symlink_stress_batch(fs, symlinks_dir.clone(), updates); + write_op.read_strongly_consistent().await?; + apply_effects(write_op).await?; + } + + anyhow::Ok(()) + }) + .await + .unwrap(); + + tt.stop_and_wait().await; + } } // Tests helpers for denied_path tests @@ -3142,9 +3195,9 @@ mod tests { .write_all(b"deep secret") .unwrap(); - let root: RcStr = path.to_str().unwrap().into(); + let root = RcStr::from(path.to_str().unwrap()); // denied_path should be relative to root, using unix separators - let denied_path: RcStr = rcstr!("denied_dir"); + let denied_path = rcstr!("denied_dir"); (scratch, root, denied_path) } diff --git a/turbopack/crates/turbo-tasks-fs/src/retry.rs b/turbopack/crates/turbo-tasks-fs/src/retry.rs index fd29b0f5c26d69..82622fc4e55a09 100644 --- a/turbopack/crates/turbo-tasks-fs/src/retry.rs +++ b/turbopack/crates/turbo-tasks-fs/src/retry.rs @@ -1,21 +1,36 @@ use std::{ io::{self, ErrorKind}, - path::{Path, PathBuf}, time::Duration, }; const MAX_RETRY_ATTEMPTS: usize = 10; -pub(crate) async fn retry_blocking(path: PathBuf, func: F) -> io::Result -where - F: Fn(&Path) -> io::Result + Send + 'static, - R: Send + 'static, -{ - let mut attempt = 1; +/// Retries a blocking io operation up to `MAX_RETRY_ATTEMPTS` in a loop. Retries upon +/// [`ErrorKind::PermissionDenied`] or [`ErrorKind::WouldBlock`]. This default behavior is +/// implemented by [`can_retry`]. +/// +/// Retry logic is rarely useful on POSIX operating systems, but is often useful on Windows with +/// NTFS. E.g. a file deletion may fail because an AV process has opened the file, and opened files +/// cannot be deleted on Windows. Retries are the only mitigation for such issues. +/// +/// This used to use [`tokio::task::spawn_blocking`], but now the IO operation blocks the current +/// thread, as we already wrap callers of this function in +/// [`crate::ConcurrencyLimitedExt::concurrency_limited`] and it +/// appears to be faster to block the tokio thread than to spawn. Most of our IO operations are very +/// short anyways. See this PR: . +pub(crate) async fn retry_blocking(func: impl FnMut() -> io::Result) -> io::Result { + retry_blocking_custom(func, can_retry).await +} +/// A customizable version of [`retry_blocking`] that allows retrying on arbitrary errors. +pub(crate) async fn retry_blocking_custom( + mut func: impl FnMut() -> Result, + mut can_retry: impl FnMut(&E) -> bool, +) -> Result { + let mut attempt = 1; loop { - return match func(&path) { - Ok(r) => Ok(r), + return match func() { + Ok(val) => Ok(val), Err(err) => { if attempt < MAX_RETRY_ATTEMPTS && can_retry(&err) { tokio::time::sleep(get_retry_wait_time(attempt)).await; @@ -29,7 +44,9 @@ where } } -fn can_retry(err: &io::Error) -> bool { +/// The default implementation of error checking used by [`retry_blocking`]. Returns true if it +/// would make sense to retry a failed IO operation. +pub fn can_retry(err: &io::Error) -> bool { matches!( err.kind(), ErrorKind::PermissionDenied | ErrorKind::WouldBlock diff --git a/turbopack/crates/turbo-tasks-fuzz/src/fs_watcher.rs b/turbopack/crates/turbo-tasks-fuzz/src/fs_watcher.rs index 3209f44a244d19..fedb4dcf1cfa07 100644 --- a/turbopack/crates/turbo-tasks-fuzz/src/fs_watcher.rs +++ b/turbopack/crates/turbo-tasks-fuzz/src/fs_watcher.rs @@ -102,8 +102,7 @@ pub async fn run(args: FsWatcher) -> anyhow::Result<()> { tt.run_once(async move { let invalidations = TransientInstance::new(PathInvalidations::default()); - let fs_root_rcstr = RcStr::from(fs_root.to_str().unwrap()); - let project_fs = disk_file_system_operation(fs_root_rcstr.clone()) + let project_fs = disk_file_system_operation(RcStr::from(fs_root.to_str().unwrap())) .resolve_strongly_consistent() .await?; let project_root = disk_file_system_root_operation(project_fs) diff --git a/turbopack/crates/turbo-tasks-fuzz/src/main.rs b/turbopack/crates/turbo-tasks-fuzz/src/main.rs index d82325d40b0936..5b2d92a0150e99 100644 --- a/turbopack/crates/turbo-tasks-fuzz/src/main.rs +++ b/turbopack/crates/turbo-tasks-fuzz/src/main.rs @@ -1,6 +1,7 @@ #![cfg_attr(windows, feature(junction_point))] mod fs_watcher; +mod symlink_stress; use clap::{Parser, Subcommand}; @@ -22,6 +23,8 @@ struct Cli { enum Commands { /// Continuously fuzzes the filesystem watcher until ctrl+c'd. FsWatcher(fs_watcher::FsWatcher), + /// Stress tests symlink/junction writes in a tight loop. + SymlinkStress(symlink_stress::SymlinkStress), } #[tokio::main] @@ -30,5 +33,6 @@ async fn main() -> anyhow::Result<()> { match cli.command { Commands::FsWatcher(args) => fs_watcher::run(args).await, + Commands::SymlinkStress(args) => symlink_stress::run(args).await, } } diff --git a/turbopack/crates/turbo-tasks-fuzz/src/symlink_stress.rs b/turbopack/crates/turbo-tasks-fuzz/src/symlink_stress.rs new file mode 100644 index 00000000000000..91d6667f115339 --- /dev/null +++ b/turbopack/crates/turbo-tasks-fuzz/src/symlink_stress.rs @@ -0,0 +1,216 @@ +use std::{ + path::{Path, PathBuf}, + time::{Duration, Instant}, +}; + +const PROGRESS_INTERVAL: Duration = Duration::from_secs(1); + +use clap::Args; +use rand::{Rng, SeedableRng}; +use turbo_rcstr::{RcStr, rcstr}; +use turbo_tasks::{ResolvedVc, TryJoinIterExt, Vc, apply_effects}; +use turbo_tasks_backend::{BackendOptions, TurboTasksBackend, noop_backing_storage}; +use turbo_tasks_fs::{DiskFileSystem, FileSystem, FileSystemPath, LinkContent, LinkType}; + +#[derive(Args)] +pub struct SymlinkStress { + #[arg(long)] + fs_root: PathBuf, + /// Number of target directories symlinks can point to. + #[arg(long, default_value_t = 20)] + target_count: usize, + /// Number of symlinks to create and update. + #[arg(long, default_value_t = 50)] + symlink_count: usize, + /// Number of symlink writes to perform in parallel. + #[arg(long, default_value_t = 16)] + parallelism: usize, + /// How long to run the stress test for. + #[arg(long, default_value_t = 5)] + duration_secs: u64, +} + +pub async fn run(args: SymlinkStress) -> anyhow::Result<()> { + std::fs::create_dir(&args.fs_root)?; + let fs_root = args.fs_root.canonicalize()?; + let _guard = FsCleanup { + path: &fs_root.clone(), + }; + + // Create target directories that symlinks will point to + let targets_dir = fs_root.join("_targets"); + std::fs::create_dir(&targets_dir)?; + for i in 0..args.target_count { + std::fs::create_dir(targets_dir.join(i.to_string()))?; + } + + // Create symlinks directory + let symlinks_dir = fs_root.join("_symlinks"); + std::fs::create_dir(&symlinks_dir)?; + + let tt = turbo_tasks::TurboTasks::new(TurboTasksBackend::new( + BackendOptions::default(), + noop_backing_storage(), + )); + + let target_count = args.target_count; + let symlink_count = args.symlink_count; + let parallelism = args.parallelism; + let duration = Duration::from_secs(args.duration_secs); + + tt.run_once(async move { + let project_fs = disk_file_system_operation(RcStr::from(fs_root.to_str().unwrap())) + .resolve_strongly_consistent() + .await?; + let project_root = disk_file_system_root_operation(project_fs) + .resolve_strongly_consistent() + .await? + .owned() + .await?; + + // Create initial symlinks via turbo-tasks, all pointing to target 0 + let symlinks_path = project_root.join("_symlinks")?; + let initial_target = RcStr::from("../_targets/0"); + + println!("creating {symlink_count} initial symlinks..."); + + let initial_op = + create_initial_symlinks_operation(symlinks_path.clone(), symlink_count, initial_target); + initial_op.read_strongly_consistent().await?; + apply_effects(initial_op).await?; + + println!( + "starting stress test with parallelism={} for {}s...", + parallelism, + duration.as_secs() + ); + + let mut rng = rand::rngs::SmallRng::from_rng(&mut rand::rng()); + let mut total_writes: u64 = 0; + let mut last_progress_writes: u64 = 0; + let start_time = Instant::now(); + let mut last_progress_time = start_time; + + loop { + // Check if we've reached the duration limit + if start_time.elapsed() >= duration { + break; + } + + // Generate random symlink updates for this batch + let updates: Vec<(usize, usize)> = (0..parallelism) + .map(|_| { + let symlink_idx = rng.random_range(0..symlink_count); + let target_idx = rng.random_range(0..target_count); + (symlink_idx, target_idx) + }) + .collect(); + + // Execute writes in parallel via turbo-tasks + let write_op = write_symlinks_batch_operation(symlinks_path.clone(), updates); + write_op.read_strongly_consistent().await?; + apply_effects(write_op).await?; + + total_writes += parallelism as u64; + + // Print progress every PROGRESS_INTERVAL + let now = Instant::now(); + if now.duration_since(last_progress_time) >= PROGRESS_INTERVAL { + let interval_writes = total_writes - last_progress_writes; + let interval_duration = now.duration_since(last_progress_time); + let writes_per_sec = interval_writes as f64 / interval_duration.as_secs_f64(); + println!( + "{:.1}s: {} writes, {:.0} writes/sec", + start_time.elapsed().as_secs_f64(), + total_writes, + writes_per_sec + ); + last_progress_time = now; + last_progress_writes = total_writes; + } + } + + // Final summary + let elapsed = start_time.elapsed(); + let writes_per_sec = total_writes as f64 / elapsed.as_secs_f64(); + println!( + "completed {} symlink writes in {:.2}s ({:.0} writes/sec)", + total_writes, + elapsed.as_secs_f64(), + writes_per_sec + ); + + Ok(()) + }) + .await?; + + tt.stop_and_wait().await; + Ok(()) +} + +#[turbo_tasks::function(operation)] +fn disk_file_system_operation(fs_root: RcStr) -> Vc { + DiskFileSystem::new(rcstr!("project"), fs_root) +} + +#[turbo_tasks::function(operation)] +fn disk_file_system_root_operation(fs: ResolvedVc) -> Vc { + fs.root() +} + +#[turbo_tasks::function(operation)] +async fn create_initial_symlinks_operation( + symlinks_dir: FileSystemPath, + count: usize, + target: RcStr, +) -> anyhow::Result<()> { + (0..count) + .map(|i| write_symlink(symlinks_dir.clone(), i, target.clone())) + .try_join() + .await?; + Ok(()) +} + +#[turbo_tasks::function(operation)] +async fn write_symlinks_batch_operation( + symlinks_dir: FileSystemPath, + updates: Vec<(usize, usize)>, +) -> anyhow::Result<()> { + updates + .into_iter() + .map(|(symlink_idx, target_idx)| { + let target = RcStr::from(format!("../_targets/{}", target_idx)); + write_symlink(symlinks_dir.clone(), symlink_idx, target) + }) + .try_join() + .await?; + Ok(()) +} + +#[turbo_tasks::function] +async fn write_symlink( + symlinks_dir: FileSystemPath, + symlink_idx: usize, + target: RcStr, +) -> anyhow::Result<()> { + let symlink_path = symlinks_dir.join(&symlink_idx.to_string())?; + let link_content = LinkContent::Link { + target, + link_type: LinkType::DIRECTORY, + }; + symlink_path + .fs() + .write_link(symlink_path.clone(), link_content.cell()) + .await?; + Ok(()) +} + +struct FsCleanup<'a> { + path: &'a Path, +} + +impl Drop for FsCleanup<'_> { + fn drop(&mut self) { + std::fs::remove_dir_all(self.path).unwrap(); + } +} diff --git a/turbopack/crates/turbo-tasks-macros/src/derive/key_value_pair_macro.rs b/turbopack/crates/turbo-tasks-macros/src/derive/key_value_pair_macro.rs index e16cf22b266402..64d1ca3924151b 100644 --- a/turbopack/crates/turbo-tasks-macros/src/derive/key_value_pair_macro.rs +++ b/turbopack/crates/turbo-tasks-macros/src/derive/key_value_pair_macro.rs @@ -12,8 +12,6 @@ pub fn derive_key_value_pair(input: TokenStream) -> TokenStream { let value_name = Ident::new(&format!("{}Value", input.ident), input.ident.span()); let value_ref_name = Ident::new(&format!("{}ValueRef", input.ident), input.ident.span()); let value_ref_mut_name = Ident::new(&format!("{}ValueRefMut", input.ident), input.ident.span()); - let iter_name = Ident::new(&format!("{}Iter", input.ident), input.ident.span()); - let storage_name = Ident::new(&format!("{}Storage", input.ident), input.ident.span()); let variant_names = input .variants @@ -67,101 +65,6 @@ pub fn derive_key_value_pair(input: TokenStream) -> TokenStream { let value_ref_mut_decl = mut_ref_field_declarations(&value_fields); let value_ref_fields = ref_fields(&value_fields); - let storage = key_fields - .iter() - .zip(value_fields.iter()) - .zip(variant_names.iter()) - .map(|((key_fields, value_fields), variant_name)| { - let value_types = value_fields - .iter() - .map(|field| { - let ty = &field.ty; - quote! { - #ty - } - }) - .collect::>(); - let key_types = key_fields - .iter() - .map(|field| { - let ty = &field.ty; - quote! { - #ty - } - }) - .collect::>(); - let value_fields = value_fields - .iter() - .map(|field| { - let ident = field.ident.as_ref().unwrap(); - quote! { - #ident - } - }) - .collect::>(); - let key_fields = key_fields - .iter() - .map(|field| { - let ident = field.ident.as_ref().unwrap(); - quote! { - #ident - } - }) - .collect::>(); - match (key_types.len(), value_types.len()) { - (0, 1) => StorageDecl { - decl: quote! { - OptionStorage<#(#value_types)*> - }, - key: quote! { - () - }, - pattern: quote! { - #ident::#variant_name { #(#value_fields)* } - }, - key_pattern: quote! {}, - }, - (1, 1) => StorageDecl { - decl: quote! { - AutoMapStorage<#(#key_types)*, #(#value_types)*> - }, - key: quote! { - #(#key_fields)* - }, - pattern: quote! { - #ident::#variant_name { #(#key_fields)*, #(#value_fields)* } - }, - key_pattern: quote! { - #(#key_fields)* - }, - }, - (_, 1) => StorageDecl { - decl: quote! { - AutoMapStorage<(#(#key_types),*), #(#value_types)*> - }, - key: quote! { - (#(#key_fields),*) - }, - pattern: quote! { - #ident::#variant_name { #(#key_fields),*, #(#value_fields)* } - }, - key_pattern: quote! { - #(#key_fields),* - }, - }, - _ => unreachable!(), - } - }) - .collect::>(); - - let storage_decl = storage.iter().map(|decl| &decl.decl).collect::>(); - let storage_key = storage.iter().map(|decl| &decl.key).collect::>(); - let storage_pattern = storage.iter().map(|decl| &decl.pattern).collect::>(); - let storage_key_pattern = storage - .iter() - .map(|decl| &decl.key_pattern) - .collect::>(); - quote! { #[automatically_derived] impl turbo_tasks::KeyValuePair for #ident { @@ -315,214 +218,6 @@ pub fn derive_key_value_pair(input: TokenStream) -> TokenStream { } } - #[derive(Debug, Clone)] - #vis enum #storage_name { - #( - #variant_names { - storage: #storage_decl - }, - )* - } - - #[automatically_derived] - impl #storage_name { - pub fn new(ty: #type_name) -> Self { - match ty { - #( - #type_name::#variant_names => #storage_name::#variant_names { storage: Default::default() }, - )* - } - } - - pub fn ty(&self) -> #type_name { - match self { - #( - #storage_name::#variant_names { .. } => #type_name::#variant_names, - )* - } - } - - pub fn add(&mut self, item: #ident) -> bool { - match (self, item) { - #( - (#storage_name::#variant_names { storage }, #storage_pattern) => { - storage.add(#storage_key, value) - } - )* - _ => unreachable!(), - } - } - - pub fn insert(&mut self, item: #ident) -> Option<#value_name> { - match (self, item) { - #( - (#storage_name::#variant_names { storage }, #storage_pattern) => { - storage.insert(#storage_key, value).map(|value| #value_name::#variant_names { value }) - } - )* - _ => unreachable!(), - } - } - - pub fn extend(&mut self, iterator: impl Iterator) -> bool { - match self { - #( - #storage_name::#variant_names { storage } => { - storage.extend(iterator.map(|item| match item { - #storage_pattern => (#storage_key, value), - _ => unreachable!(), - })) - } - )* - _ => unreachable!(), - } - } - - pub fn remove(&mut self, key: &#key_name) -> Option<#value_name> { - match (self, *key) { - #( - (#storage_name::#variant_names { storage }, #key_name::#variant_names { #storage_key_pattern }) => { - storage.remove(&#storage_key).map(|value| #value_name::#variant_names { value }) - } - )* - _ => unreachable!(), - } - } - - pub fn contains_key(&self, key: &#key_name) -> bool { - match (self, *key) { - #( - (#storage_name::#variant_names { storage }, #key_name::#variant_names { #storage_key_pattern }) => { - storage.contains_key(&#storage_key) - } - )* - _ => unreachable!(), - } - } - - pub fn get(&self, key: &#key_name) -> Option<#value_ref_name> { - match (self, *key) { - #( - (#storage_name::#variant_names { storage }, #key_name::#variant_names { #storage_key_pattern }) => { - storage.get(&#storage_key).map(|value| #value_ref_name::#variant_names { value }) - } - )* - _ => unreachable!(), - } - } - - pub fn get_mut(&mut self, key: &#key_name) -> Option<#value_ref_mut_name> { - match (self, *key) { - #( - (#storage_name::#variant_names { storage }, #key_name::#variant_names { #storage_key_pattern }) => { - storage.get_mut(&#storage_key).map(|value| #value_ref_mut_name::#variant_names { value }) - } - )* - _ => unreachable!(), - } - } - - pub fn get_mut_or_insert_with(&mut self, key: #key_name, insert_with: impl FnOnce() -> #value_name) -> #value_ref_mut_name { - match (self, key) { - #( - (#storage_name::#variant_names { storage }, #key_name::#variant_names { #storage_key_pattern }) => { - #value_ref_mut_name::#variant_names { value: storage - .get_mut_or_insert_with(#storage_key, || { - let #value_name::#variant_names { value } = insert_with() else { - unreachable!(); - }; - value - }) - } - } - )* - _ => unreachable!(), - } - } - - pub fn update(&mut self, key: #key_name, update: impl FnOnce(Option<#value_name>) -> Option<#value_name>) { - match (self, key) { - #( - (#storage_name::#variant_names { storage }, #key_name::#variant_names { #storage_key_pattern }) => { - storage.update(#storage_key, |old| { - let old = old.map(|value| #value_name::#variant_names { value }); - if let Some(#value_name::#variant_names { value }) = update(old) { - Some(value) - } else { - None - } - }) - } - )* - _ => unreachable!(), - } - } - - pub fn shrink_to_fit(&mut self) { - match self { - #( - #storage_name::#variant_names { storage } => { - storage.shrink_to_fit(); - } - )* - } - } - - pub fn is_empty(&self) -> bool { - match self { - #( - #storage_name::#variant_names { storage } => { - storage.is_empty() - } - )* - } - } - - pub fn len(&self) -> usize { - match self { - #( - #storage_name::#variant_names { storage } => { - storage.len() - } - )* - } - } - - pub fn iter(&self) -> #iter_name { - match self { - #( - #storage_name::#variant_names { storage } => { - #iter_name::#variant_names(storage.iter()) - } - )* - } - } - } - - #vis enum #iter_name<'l> { - #( - #variant_names(<#storage_decl as Storage>::Iterator<'l>), - )* - } - - #[automatically_derived] - impl<'l> Iterator for #iter_name<'l> { - type Item = (#key_name, #value_ref_name<'l>); - - fn next(&mut self) -> Option { - match self { - #( - #iter_name::#variant_names(iter) => { - iter.next() - .map(|(&#storage_key, value)| ( - #key_name::#variant_names { #storage_key_pattern }, - #value_ref_name::#variant_names { value } - )) - } - )* - } - } - } } .into() } @@ -653,10 +348,3 @@ fn mut_ref_field_declarations(fields: &[Vec<&syn::Field>]) -> Vec>() } - -struct StorageDecl { - decl: proc_macro2::TokenStream, - key: proc_macro2::TokenStream, - pattern: proc_macro2::TokenStream, - key_pattern: proc_macro2::TokenStream, -} diff --git a/turbopack/crates/turbo-tasks-macros/src/derive/task_storage_macro.rs b/turbopack/crates/turbo-tasks-macros/src/derive/task_storage_macro.rs index afdeb50978a7f5..d9dc5f1ab676a5 100644 --- a/turbopack/crates/turbo-tasks-macros/src/derive/task_storage_macro.rs +++ b/turbopack/crates/turbo-tasks-macros/src/derive/task_storage_macro.rs @@ -55,11 +55,16 @@ struct FieldInfo { /// If true, filter out values that reference transient tasks during encoding. /// For direct fields: skip encoding if value.is_transient() returns true. /// For collections: filter out entries where key/value is_transient() returns true. - /// For AutoMultimap: filter is always applied to inner set values automatically. filter_transient: bool, /// If true, use Default::default() semantics instead of Option for inline direct fields. /// The field type should be T (not Option), and empty is represented by T::default(). use_default: bool, + /// The CachedDataItem variant name for adapter code generation. + /// If None, no adapter code is generated for this field. + cached_data_variant: Option, + /// The key field names in CachedDataItemKey for collection types. + /// E.g., ["task"], ["target", "key"], ["cell", "key", "task"]. + key_fields: Option>, } impl FieldInfo { @@ -68,6 +73,16 @@ impl FieldInfo { self.storage_type == StorageType::Flag } + /// Whether this field has a CachedDataItem variant (for adapter code generation). + fn has_cached_data_variant(&self) -> bool { + self.cached_data_variant.is_some() + } + + /// Get the CachedDataItem variant identifier (panics if none). + fn cached_data_variant_ident(&self) -> &Ident { + self.cached_data_variant.as_ref().unwrap() + } + /// Whether this field is transient (not serialized, in-memory only). fn is_transient(&self) -> bool { self.category == Category::Transient @@ -290,6 +305,92 @@ impl FieldInfo { proc_macro2::Span::call_site(), ) } + fn shrink_ident(&self) -> syn::Ident { + self.prefixed_ident("shrink") + } + + // ========================================================================= + // Key Fields Helpers (for CachedDataItem adapter code generation) + // ========================================================================= + + /// Generate the key pattern for match arms in CachedDataItemKey. + /// + /// For single key field: `{ task }` + /// For multiple key fields: `{ cell, key, task }` + fn key_pattern(&self) -> TokenStream { + match &self.key_fields { + None => quote! {}, + Some(fields) => { + quote! { #(#fields),* } + } + } + } + + /// Generate the key expression for use in set/map insert operations (moves values). + /// + /// For single key field: `task` + /// For multiple key fields: `(cell, key, task)` + fn key_expr(&self) -> TokenStream { + match &self.key_fields { + None => quote! {}, + Some(fields) if fields.len() == 1 => { + let f = &fields[0]; + quote! { #f } + } + Some(fields) => { + quote! { (#(#fields),*) } + } + } + } + + /// Generate the key expression for use when fields are bound by reference (e.g., in + /// get/contains). Clones the values to construct a tuple by value. + /// + /// For single key field: `target.clone()` + /// For multiple key fields: `(target.clone(), key.clone())` + fn key_expr_cloned(&self) -> TokenStream { + match &self.key_fields { + None => quote! {}, + Some(fields) if fields.len() == 1 => { + let f = &fields[0]; + quote! { #f.clone() } + } + Some(fields) => { + let cloned: Vec<_> = fields.iter().map(|f| quote! { #f.clone() }).collect(); + quote! { (#(#cloned),*) } + } + } + } + + /// Generate the key expression with clone/copy for constructing CachedDataItemKey. + /// + /// For single key field: `task: *task` + /// For multiple key fields: `cell: *cell, key: *key, task: *task` + fn key_construction(&self) -> TokenStream { + match &self.key_fields { + None => quote! {}, + Some(fields) => { + let constructs: Vec<_> = fields.iter().map(|f| quote! { #f: *#f }).collect(); + quote! { #(#constructs),* } + } + } + } + + /// Generate key construction for owned values (no dereference). + /// + /// For single key field: `task: task` + /// For multiple key fields: `cell: cell, key: key, task: task` + /// + /// Used when the key is already owned (e.g., from iter methods that return values not refs). + fn key_construction_owned(&self) -> TokenStream { + match &self.key_fields { + None => quote! {}, + Some(fields) => { + let constructs: Vec<_> = fields.iter().map(|f| quote! { #f: #f }).collect(); + quote! { #(#constructs),* } + } + } + } } #[derive(Debug, Clone, PartialEq, Eq)] @@ -338,6 +439,8 @@ fn parse_field_storage_attributes(field: &syn::Field) -> FieldInfo { let mut inline = false; // Default is lazy (not inline) let mut filter_transient = false; let mut use_default = false; + let mut cached_data_variant: Option = None; + let mut key_fields: Option> = None; // Find and parse the field attribute if let Some(attr) = field.attrs.iter().find(|attr| { @@ -412,6 +515,31 @@ fn parse_field_storage_attributes(field: &syn::Field) -> FieldInfo { }); } } + "variant" => { + if let syn::Expr::Lit(syn::ExprLit { + lit: syn::Lit::Str(lit_str), + .. + }) = &nv.value + { + cached_data_variant = + Some(Ident::new(&lit_str.value(), lit_str.span())); + } + } + "key_field" => { + if let syn::Expr::Lit(syn::ExprLit { + lit: syn::Lit::Str(lit_str), + .. + }) = &nv.value + { + let fields: Vec = lit_str + .value() + .split(',') + .map(|s| Ident::new(s.trim(), lit_str.span())) + .collect(); + key_fields = Some(fields); + } + } + other => { meta.span() .unwrap() @@ -420,7 +548,7 @@ fn parse_field_storage_attributes(field: &syn::Field) -> FieldInfo { )) .emit(); } - } + }; } Meta::Path(path) => { let Some(ident) = path.get_ident() else { @@ -515,6 +643,8 @@ fn parse_field_storage_attributes(field: &syn::Field) -> FieldInfo { lazy: !inline, // Default is lazy; inline = true means lazy = false filter_transient, use_default, + cached_data_variant, + key_fields, } } @@ -604,6 +734,21 @@ impl GroupedFields { .iter() .filter(move |f| !f.is_flag() && f.lazy && !f.is_transient() && f.category == category) } + + // ========================================================================= + // CachedDataItem adapter iterators + // ========================================================================= + + /// Returns an iterator over all fields that have a CachedDataItem variant. + /// These fields will generate adapter code for the CachedDataItem API. + fn fields_with_variant(&self) -> impl Iterator { + self.fields.iter().filter(|f| f.has_cached_data_variant()) + } + + /// Returns true if any fields have a CachedDataItem variant. + fn has_fields_with_variant(&self) -> bool { + self.fields.iter().any(|f| f.has_cached_data_variant()) + } } // ============================================================================= @@ -922,7 +1067,7 @@ fn generate_typed_storage_struct(grouped_fields: &GroupedFields) -> TokenStream let lazy_field = if has_lazy { quote! { /// Lazily-allocated fields stored in a single Vec for memory efficiency - pub(crate) lazy: Vec, + lazy: Vec, } } else { quote! {} @@ -938,7 +1083,7 @@ fn generate_typed_storage_struct(grouped_fields: &GroupedFields) -> TokenStream /// Unified typed storage containing all task fields. /// This is designed to be embedded in the actual InnerStorage for incremental migration. #[automatically_derived] - #[derive(Debug, Clone, Default, PartialEq, turbo_tasks::ShrinkToFit)] + #[derive(Debug, Default, PartialEq, turbo_tasks::ShrinkToFit)] #[shrink_to_fit(crate = "turbo_tasks::macro_helpers::shrink_to_fit")] pub struct TaskStorage { #(#field_defs,)* @@ -1147,6 +1292,9 @@ fn generate_task_storage_accessors_trait(grouped_fields: &GroupedFields) -> Toke trait_methods.extend(generate_flag_trait_accessor_methods(field)); } + // Generate CachedDataItem adapter methods + let adapter_methods = generate_cached_data_adapter_trait_methods(grouped_fields); + quote! { /// Trait for typed storage accessors. /// @@ -1198,6 +1346,8 @@ fn generate_task_storage_accessors_trait(grouped_fields: &GroupedFields) -> Toke } #trait_methods + + #adapter_methods } } } @@ -1220,8 +1370,10 @@ fn generate_trait_accessor_methods(field: &FieldInfo) -> TokenStream { generate_direct_accessors(field) } StorageType::AutoSet => { - // For AutoSet types, generate read-only accessor plus add/remove/has/iter/len/is_empty + // For AutoSet types, generate read-only accessor, mutable accessor, and + // add/remove/has/iter/len/is_empty let ref_name = field.ref_ident(); + let mut_name = field.mut_ident(); let (return_type, doc_comment) = if is_option { ( @@ -1236,24 +1388,40 @@ fn generate_trait_accessor_methods(field: &FieldInfo) -> TokenStream { ) }; + let track_modification = field.track_modification_call(); + let base_accessor = quote! { #[doc = #doc_comment] fn #ref_name(&self) -> #return_type { #check_access #ref_expr } + + /// Get a mutable reference to the collection (allocates if needed for lazy fields). + /// + /// Tracks modification pessimistically - assumes caller will mutate. + /// TODO: try to remove this method, tracking mutations before the mutation interferes with snapshotting logic + fn #mut_name(&mut self) -> &mut #field_type { + #check_access + #track_modification + #mut_expr + } }; let set_ops = generate_autoset_ops(field); + let shrink_accessor = generate_shrink_accessor(field); quote! { #base_accessor #set_ops + #shrink_accessor } } StorageType::CounterMap => { - // For CounterMap types, generate read-only accessor plus mutation methods + // For CounterMap types, generate read-only accessor, mutable accessor, and typed + // mutation methods let ref_name = field.ref_ident(); + let mut_name = field.mut_ident(); let (return_type, doc_comment) = if is_option { ( @@ -1268,19 +1436,33 @@ fn generate_trait_accessor_methods(field: &FieldInfo) -> TokenStream { ) }; + let track_modification = field.track_modification_call(); + let base_accessor = quote! { #[doc = #doc_comment] fn #ref_name(&self) -> #return_type { #check_access #ref_expr } + + /// Get a mutable reference to the collection (allocates if needed for lazy fields). + /// + /// Tracks modification pessimistically - assumes caller will mutate. + /// TODO: try to remove this method, tracking mutations before the mutation interferes with snapshotting logic + fn #mut_name(&mut self) -> &mut #field_type { + #check_access + #track_modification + #mut_expr + } }; let countermap_ops = generate_countermap_ops(field); + let shrink_accessor = generate_shrink_accessor(field); quote! { #base_accessor #countermap_ops + #shrink_accessor } } StorageType::AutoMap => { @@ -1300,6 +1482,8 @@ fn generate_trait_accessor_methods(field: &FieldInfo) -> TokenStream { ) }; + let track_modification = field.track_modification_call(); + let base_accessor = quote! { #[doc = #ref_doc] fn #ref_name(&self) -> #return_type { @@ -1309,19 +1493,22 @@ fn generate_trait_accessor_methods(field: &FieldInfo) -> TokenStream { /// Get a mutable reference to the collection (allocates if needed for lazy fields). /// - /// Note: This does NOT track modifications. Call `track_modification` after - /// making changes to ensure persistence. + /// Tracks modification pessimistically - assumes caller will mutate. + /// TODO: try to remove this method, tracking mutations before the mutation interferes with snapshotting logic fn #mut_name(&mut self) -> &mut #field_type { #check_access + #track_modification #mut_expr } }; let automap_ops = generate_automap_ops(field); + let shrink_accessor = generate_shrink_accessor(field); quote! { #base_accessor #automap_ops + #shrink_accessor } } StorageType::Flag => { @@ -1366,23 +1553,54 @@ fn generate_direct_accessors(field: &FieldInfo) -> TokenStream { quote! { #field_type } }; - // Generate get_mut accessor only for lazy fields - // (for inline fields, use set/take instead) - let get_mut_accessor = if !field.is_inline() { + // Generate get_mut accessor for all direct fields + let get_mut_accessor = { let get_mut_name = field.get_mut_ident(); - let get_mut_expr = field.direct_get_mut_expr(); - quote! { - /// Get a mutable reference to the field value (if present). - /// - /// Note: This does NOT track modifications. Call `track_modification` after - /// making changes to ensure persistence. - fn #get_mut_name(&mut self) -> Option<&mut #value_type> { - #check_access - #get_mut_expr + if field.is_inline() { + // For inline fields, access the field directly + let field_name = &field.field_name; + if field.use_default { + // For fields with default semantics, always return Some(&mut self.field) + quote! { + /// Get a mutable reference to the field value. + /// + /// Tracks modification pessimistically - assumes caller will mutate. + /// TODO: try to remove this method, tracking mutations before the mutation interferes with snapshotting logic. + /// If this is needed then we need to use a guard struct that tracks `DerefMut` calls and calls track_modification + /// in Drop + fn #get_mut_name(&mut self) -> Option<&mut #value_type> { + #check_access + #track_modification + Some(&mut self.typed_mut().#field_name) + } + } + } else { + // For Option fields, return as_mut() + quote! { + /// Get a mutable reference to the field value (if present). + /// + /// Tracks modification pessimistically - assumes caller will mutate. + fn #get_mut_name(&mut self) -> Option<&mut #value_type> { + #check_access + #track_modification + self.typed_mut().#field_name.as_mut() + } + } + } + } else { + // For lazy fields, use the existing get_mut expression + let get_mut_expr = field.direct_get_mut_expr(); + quote! { + /// Get a mutable reference to the field value (if present). + /// + /// Tracks modification pessimistically - assumes caller will mutate. + fn #get_mut_name(&mut self) -> Option<&mut #value_type> { + #check_access + #track_modification + #get_mut_expr + } } } - } else { - quote! {} }; quote! { @@ -1887,6 +2105,45 @@ fn generate_automap_ops(field: &FieldInfo) -> TokenStream { } } +/// Generate shrink_to_fit accessor for a collection field. +/// +/// For collection fields (AutoSet, AutoMap, CounterMap), generates a `shrink_{field_name}()` +/// method that calls `shrink_to_fit()` on the underlying collection. +/// +/// This does NOT track modifications or check access since shrinking doesn't +/// semantically change the data - it only reduces memory usage. +/// +/// For lazy fields, avoids allocation if the collection doesn't exist. +fn generate_shrink_accessor(field: &FieldInfo) -> TokenStream { + let shrink_name = field.shrink_ident(); + let field_name = &field.field_name; + let is_lazy = field.lazy; + + let shrink_body = if is_lazy { + // For lazy fields, use find_lazy_mut to avoid allocating + let extractor = field.lazy_extractor_closure(); + quote! { + if let Some(collection) = self.typed_mut().find_lazy_mut(#extractor) { + collection.shrink_to_fit(); + } + } + } else { + // For inline fields, access the field directly + quote! { + self.typed_mut().#field_name.shrink_to_fit(); + } + }; + + quote! { + /// Shrink the collection to fit its current contents, releasing excess memory. + /// + /// This does NOT track modifications since it doesn't change the data semantically. + fn #shrink_name(&mut self) { + #shrink_body + } + } +} + /// Extract the inner type from Option, or return the type as-is if not Option fn extract_option_inner_type(ty: &Type) -> TokenStream { // Try to parse as Option and extract T @@ -2597,3 +2854,1124 @@ fn generate_snapshot_restore_methods(grouped_fields: &GroupedFields) -> TokenStr } } } + +// ============================================================================= +// CachedDataItem Adapter Code Generation +// ============================================================================= + +/// Generate the CachedDataItem adapter methods for the TaskStorageAccessors trait. +/// +/// These methods provide the CachedDataItem API (add, insert, get, remove, etc.) +/// using the typed accessor methods from the trait. This enables proper access +/// tracking via check_access() and track_modification(). +fn generate_cached_data_adapter_trait_methods( + grouped_fields: &GroupedFields, +) -> proc_macro2::TokenStream { + // Only generate if there are fields with variants + if !grouped_fields.has_fields_with_variant() { + return quote! {}; + } + + // Generate match arms for each method + let insert_kv_arms = generate_insert_kv_arms(grouped_fields); + let add_arms = generate_add_arms(grouped_fields); + let get_arms = generate_get_arms(grouped_fields); + let remove_arms = generate_remove_arms(grouped_fields); + let get_mut_arms = generate_get_mut_arms(grouped_fields); + let iter_arms = generate_iter_arms(grouped_fields); + let count_arms = generate_count_arms(grouped_fields); + let extend_arms = generate_extend_arms(grouped_fields); + let extract_if_arms = generate_extract_if_arms(grouped_fields); + + quote! { + // ========================================================================= + // CachedDataItem Adapter Methods + // + // These methods provide backward compatibility with the CachedDataItem API + // while using typed accessors internally for proper access tracking. + // ========================================================================= + + /// Add a CachedDataItem to storage. + /// + /// Returns `true` if the item was newly added, `false` if it already existed. + /// Does NOT overwrite if the key already exists. + fn add(&mut self, item: crate::data::CachedDataItem) -> bool { + use crate::data::{CachedDataItemKey, CachedDataItemValue}; + use turbo_tasks::KeyValuePair; + let (key, value) = item.into_key_and_value(); + match (key, value) { + #add_arms + + // Catch-all for mismatched key/value types + #[allow(unreachable_patterns)] + (key, value) => { + panic!( + "Mismatched CachedDataItem key/value types: key={key:?}, value={value:?}" + ); + } + } + } + + /// Insert a CachedDataItem, returning the old value if present. + fn insert( + &mut self, + item: crate::data::CachedDataItem, + ) -> Option { + use turbo_tasks::KeyValuePair; + let (key, value) = item.into_key_and_value(); + self.insert_kv(key, value) + } + + /// Insert a key-value pair, returning the old value if present. + fn insert_kv( + &mut self, + key: crate::data::CachedDataItemKey, + value: crate::data::CachedDataItemValue, + ) -> Option { + use crate::data::{CachedDataItemKey, CachedDataItemValue}; + match (key, value) { + #insert_kv_arms + + // Catch-all for mismatched key/value types + #[allow(unreachable_patterns)] + (key, value) => { + panic!( + "Mismatched CachedDataItem key/value types: key={key:?}, value={value:?}" + ); + } + } + } + + /// Check if a key exists in storage. + fn contains_key(&self, key: &crate::data::CachedDataItemKey) -> bool { + self.get(key).is_some() + } + + /// Check if a key exists in storage (alias for contains_key for backward compatibility). + fn has_key(&self, key: &crate::data::CachedDataItemKey) -> bool { + self.contains_key(key) + } + + /// Get a reference to a CachedDataItem value by key. + fn get( + &self, + key: &crate::data::CachedDataItemKey, + ) -> Option> { + use crate::data::{CachedDataItemKey, CachedDataItemValueRef}; + match key { + #get_arms + } + } + + /// Remove a CachedDataItem by key, returning the value if present. + fn remove( + &mut self, + key: &crate::data::CachedDataItemKey, + ) -> Option { + use crate::data::{CachedDataItemKey, CachedDataItemValue}; + match key { + #remove_arms + } + } + + /// Get a mutable reference to a CachedDataItem value by key. + fn get_mut( + &mut self, + key: &crate::data::CachedDataItemKey, + ) -> Option> { + use crate::data::{CachedDataItemKey, CachedDataItemValueRefMut}; + match key { + #get_mut_arms + } + } + + /// Update a value in-place, creating it if it doesn't exist. + fn update( + &mut self, + key: crate::data::CachedDataItemKey, + update: impl FnOnce(Option) -> Option, + ) { + use turbo_tasks::KeyValuePair; + let old_value = self.remove(&key); + if let Some(new_value) = update(old_value) { + let item = crate::data::CachedDataItem::from_key_and_value(key, new_value); + self.add(item); + } + } + + /// Get a mutable reference or insert a value created by the given closure. + fn get_mut_or_insert_with( + &mut self, + key: crate::data::CachedDataItemKey, + insert: impl FnOnce() -> crate::data::CachedDataItemValue, + ) -> crate::data::CachedDataItemValueRefMut<'_> { + use turbo_tasks::KeyValuePair; + if self.get(&key).is_none() { + let value = insert(); + self.insert_kv(key.clone(), value); + } + self.get_mut(&key).expect("just inserted") + } + + /// Count items of a specific type. + fn count(&self, ty: crate::data::CachedDataItemType) -> usize { + use crate::data::CachedDataItemType; + match ty { + #count_arms + } + } + + /// Iterate over items of a specific type. + fn iter( + &self, + ty: crate::data::CachedDataItemType, + ) -> Box)> + '_> { + use crate::data::{CachedDataItemKey, CachedDataItemType, CachedDataItemValueRef}; + + match ty { + #iter_arms + } + } + + /// Extend storage with items from an iterator. + /// Returns `true` if all items were newly added, `false` if any already existed. + fn extend( + &mut self, + ty: crate::data::CachedDataItemType, + items: impl IntoIterator, + ) -> bool { + use crate::data::{CachedDataItemKey, CachedDataItemType, CachedDataItemValue}; + use turbo_tasks::KeyValuePair; + + match ty { + #extend_arms + } + } + + /// Add a CachedDataItem that must not already exist. + /// Panics if the item already exists. + fn add_new(&mut self, item: crate::data::CachedDataItem) { + if !self.add(item) { + panic!("add_new: item already exists"); + } + } + + /// Extend with items that must all be new. + /// Panics if any item already exists. + fn extend_new( + &mut self, + _ty: crate::data::CachedDataItemType, + items: impl IntoIterator, + ) { + for item in items { + self.add_new(item); + } + } + + /// Remove items matching a predicate. + fn extract_if<'a, F>( + &'a mut self, + ty: crate::data::CachedDataItemType, + mut predicate: F, + ) -> Vec + where + F: for<'b> FnMut(crate::data::CachedDataItemKey, crate::data::CachedDataItemValueRef<'b>) -> bool + 'a, + { + use crate::data::{CachedDataItem, CachedDataItemKey, CachedDataItemType, CachedDataItemValue, CachedDataItemValueRef}; + use turbo_tasks::KeyValuePair; + + match ty { + #extract_if_arms + } + } + + } +} + +/// Generate insert_kv match arms for all fields with variants. +fn generate_insert_kv_arms(grouped_fields: &GroupedFields) -> proc_macro2::TokenStream { + let arms: Vec<_> = grouped_fields + .fields_with_variant() + .map(generate_insert_kv_arm) + .collect(); + + quote! { #(#arms)* } +} + +/// Generate a single insert_kv match arm for a field. +fn generate_insert_kv_arm(field: &FieldInfo) -> proc_macro2::TokenStream { + let variant = field.cached_data_variant_ident(); + + match &field.storage_type { + StorageType::Direct => generate_insert_kv_arm_direct(field, variant), + StorageType::AutoSet => generate_insert_kv_arm_auto_set(field, variant), + StorageType::CounterMap | StorageType::AutoMap => { + generate_insert_kv_arm_map(field, variant) + } + StorageType::Flag => generate_insert_kv_arm_flag(field, variant), + } +} + +fn generate_insert_kv_arm_direct(field: &FieldInfo, variant: &Ident) -> proc_macro2::TokenStream { + let set_name = field.set_ident(); + quote! { + ( + CachedDataItemKey::#variant {}, + CachedDataItemValue::#variant { value }, + ) => self + .#set_name(value) + .map(|v| CachedDataItemValue::#variant { value: v }), + } +} + +fn generate_insert_kv_arm_auto_set(field: &FieldInfo, variant: &Ident) -> proc_macro2::TokenStream { + let field_mut = field.mut_ident(); + let key_pattern = field.key_pattern(); + let key_expr = field.key_expr(); + quote! { + ( + CachedDataItemKey::#variant { #key_pattern }, + CachedDataItemValue::#variant { value: () }, + ) => { + let existed = !self.#field_mut().insert(#key_expr); + if existed { + Some(CachedDataItemValue::#variant { value: () }) + } else { + None + } + }, + } +} + +fn generate_insert_kv_arm_map(field: &FieldInfo, variant: &Ident) -> proc_macro2::TokenStream { + let field_mut = field.mut_ident(); + let key_pattern = field.key_pattern(); + let key_expr = field.key_expr(); + quote! { + ( + CachedDataItemKey::#variant { #key_pattern }, + CachedDataItemValue::#variant { value }, + ) => self + .#field_mut() + .insert(#key_expr, value) + .map(|v| CachedDataItemValue::#variant { value: v }), + } +} + +fn generate_insert_kv_arm_flag(field: &FieldInfo, variant: &Ident) -> proc_macro2::TokenStream { + let field_name = &field.field_name; + let set_name = field.set_ident(); + quote! { + ( + CachedDataItemKey::#variant {}, + CachedDataItemValue::#variant { value: () }, + ) => { + let existed = self.typed().flags.#field_name(); + self.typed_mut().flags.#set_name(true); + if existed { + Some(CachedDataItemValue::#variant { value: () }) + } else { + None + } + }, + } +} + +/// Generate get match arms for all fields with variants. +fn generate_get_arms(grouped_fields: &GroupedFields) -> proc_macro2::TokenStream { + let arms: Vec<_> = grouped_fields + .fields_with_variant() + .map(generate_get_arm) + .collect(); + + quote! { #(#arms)* } +} + +/// Generate a single get match arm for a field. +fn generate_get_arm(field: &FieldInfo) -> proc_macro2::TokenStream { + let variant = field.cached_data_variant_ident(); + + match &field.storage_type { + StorageType::Direct => generate_get_arm_direct(field, variant), + StorageType::AutoSet => generate_get_arm_auto_set(field, variant), + StorageType::CounterMap | StorageType::AutoMap => generate_get_arm_map(field, variant), + StorageType::Flag => generate_get_arm_flag(field, variant), + } +} + +fn generate_get_arm_direct(field: &FieldInfo, variant: &Ident) -> proc_macro2::TokenStream { + let get_name = field.get_ident(); + quote! { + CachedDataItemKey::#variant {} => self + .#get_name() + .map(|value| CachedDataItemValueRef::#variant { value }), + } +} + +fn generate_get_arm_auto_set(field: &FieldInfo, variant: &Ident) -> proc_macro2::TokenStream { + let field_name = &field.field_name; + let key_pattern = field.key_pattern(); + // Use cloned key expr since the key is passed by reference + let key_expr = field.key_expr_cloned(); + + if field.is_inline() { + quote! { + CachedDataItemKey::#variant { #key_pattern } => { + if self.#field_name().contains(&#key_expr) { + Some(CachedDataItemValueRef::#variant { value: &() }) + } else { + None + } + }, + } + } else { + quote! { + CachedDataItemKey::#variant { #key_pattern } => self.#field_name().and_then(|set| { + if set.contains(&#key_expr) { + Some(CachedDataItemValueRef::#variant { value: &() }) + } else { + None + } + }), + } + } +} + +fn generate_get_arm_map(field: &FieldInfo, variant: &Ident) -> proc_macro2::TokenStream { + let field_name = &field.field_name; + let key_pattern = field.key_pattern(); + // Use cloned key expr since the key is passed by reference + let key_expr = field.key_expr_cloned(); + + if field.is_inline() { + quote! { + CachedDataItemKey::#variant { #key_pattern } => self + .#field_name() + .get(&#key_expr) + .map(|value| CachedDataItemValueRef::#variant { value }), + } + } else { + quote! { + CachedDataItemKey::#variant { #key_pattern } => self + .#field_name() + .and_then(|map| map.get(&#key_expr)) + .map(|value| CachedDataItemValueRef::#variant { value }), + } + } +} + +fn generate_get_arm_flag(field: &FieldInfo, variant: &Ident) -> proc_macro2::TokenStream { + let field_name = &field.field_name; + quote! { + CachedDataItemKey::#variant {} => { + if self.typed().flags.#field_name() { + Some(CachedDataItemValueRef::#variant { value: &() }) + } else { + None + } + }, + } +} + +/// Generate remove match arms for all fields with variants. +fn generate_remove_arms(grouped_fields: &GroupedFields) -> proc_macro2::TokenStream { + let arms: Vec<_> = grouped_fields + .fields_with_variant() + .map(generate_remove_arm) + .collect(); + + quote! { #(#arms)* } +} + +/// Generate a single remove match arm for a field. +fn generate_remove_arm(field: &FieldInfo) -> proc_macro2::TokenStream { + let variant = field.cached_data_variant_ident(); + + match &field.storage_type { + StorageType::Direct => generate_remove_arm_direct(field, variant), + StorageType::AutoSet => generate_remove_arm_auto_set(field, variant), + StorageType::CounterMap | StorageType::AutoMap => generate_remove_arm_map(field, variant), + StorageType::Flag => generate_remove_arm_flag(field, variant), + } +} + +fn generate_remove_arm_direct(field: &FieldInfo, variant: &Ident) -> proc_macro2::TokenStream { + let take_name = field.take_ident(); + quote! { + CachedDataItemKey::#variant {} => self + .#take_name() + .map(|value| CachedDataItemValue::#variant { value }), + } +} + +fn generate_remove_arm_auto_set(field: &FieldInfo, variant: &Ident) -> proc_macro2::TokenStream { + let field_mut = field.mut_ident(); + let key_pattern = field.key_pattern(); + // Use cloned key expr since the key is passed by reference + let key_expr = field.key_expr_cloned(); + quote! { + CachedDataItemKey::#variant { #key_pattern } => { + if self.#field_mut().remove(&#key_expr) { + Some(CachedDataItemValue::#variant { value: () }) + } else { + None + } + }, + } +} + +fn generate_remove_arm_map(field: &FieldInfo, variant: &Ident) -> proc_macro2::TokenStream { + let field_mut = field.mut_ident(); + let key_pattern = field.key_pattern(); + // Use cloned key expr since the key is passed by reference + let key_expr = field.key_expr_cloned(); + quote! { + CachedDataItemKey::#variant { #key_pattern } => self + .#field_mut() + .remove(&#key_expr) + .map(|value| CachedDataItemValue::#variant { value }), + } +} + +fn generate_remove_arm_flag(field: &FieldInfo, variant: &Ident) -> proc_macro2::TokenStream { + let field_name = &field.field_name; + let set_name = field.set_ident(); + quote! { + CachedDataItemKey::#variant {} => { + let existed = self.typed().flags.#field_name(); + self.typed_mut().flags.#set_name(false); + if existed { + Some(CachedDataItemValue::#variant { value: () }) + } else { + None + } + }, + } +} + +/// Generate get_mut match arms for all fields with variants. +fn generate_get_mut_arms(grouped_fields: &GroupedFields) -> proc_macro2::TokenStream { + let arms: Vec<_> = grouped_fields + .fields_with_variant() + .map(generate_get_mut_arm) + .collect(); + + quote! { #(#arms)* } +} + +/// Generate a single get_mut match arm for a field. +/// For types that don't support mutable access (flags, sets, multimaps), generates an arm +/// that returns None. +fn generate_get_mut_arm(field: &FieldInfo) -> proc_macro2::TokenStream { + let variant = field.cached_data_variant_ident(); + + match &field.storage_type { + StorageType::Direct => generate_get_mut_arm_direct(field, variant), + StorageType::CounterMap | StorageType::AutoMap => generate_get_mut_arm_map(field, variant), + // AutoSet, and Flag don't support get_mut (value is always ()) + // But we need to include the match arm to make the match exhaustive + StorageType::AutoSet => generate_get_mut_arm_set_none(field, variant), + StorageType::Flag => generate_get_mut_arm_flag_none(field, variant), + } +} + +fn generate_get_mut_arm_direct(field: &FieldInfo, variant: &Ident) -> proc_macro2::TokenStream { + let get_mut_name = field.get_mut_ident(); + quote! { + CachedDataItemKey::#variant {} => self + .#get_mut_name() + .map(|value| CachedDataItemValueRefMut::#variant { value }), + } +} + +fn generate_get_mut_arm_map(field: &FieldInfo, variant: &Ident) -> proc_macro2::TokenStream { + let field_mut = field.mut_ident(); + let key_pattern = field.key_pattern(); + // Use cloned key expr since the key is passed by reference + let key_expr = field.key_expr_cloned(); + quote! { + CachedDataItemKey::#variant { #key_pattern } => self + .#field_mut() + .get_mut(&#key_expr) + .map(|value| CachedDataItemValueRefMut::#variant { value }), + } +} + +/// Generate a get_mut arm for AutoSet types that returns None. +/// AutoSet values are always () so mutable access is not meaningful. +fn generate_get_mut_arm_set_none(field: &FieldInfo, variant: &Ident) -> proc_macro2::TokenStream { + // Ignore all key fields with _ + let ignored_fields: Vec<_> = field + .key_fields + .as_ref() + .map(|fields| fields.iter().map(|f| quote! { #f: _ }).collect()) + .unwrap_or_default(); + quote! { + CachedDataItemKey::#variant { #(#ignored_fields),* } => None, + } +} + +/// Generate a get_mut arm for Flag types that returns None. +/// Flag values are booleans so mutable access is not meaningful. +fn generate_get_mut_arm_flag_none(_field: &FieldInfo, variant: &Ident) -> proc_macro2::TokenStream { + quote! { + CachedDataItemKey::#variant {} => None, + } +} + +/// Generate count match arms for all fields with variants. +fn generate_count_arms(grouped_fields: &GroupedFields) -> proc_macro2::TokenStream { + let arms: Vec<_> = grouped_fields + .fields_with_variant() + .map(generate_count_arm) + .collect(); + + quote! { #(#arms)* } +} + +/// Generate a single count match arm for a field. +fn generate_count_arm(field: &FieldInfo) -> proc_macro2::TokenStream { + let variant = field.cached_data_variant_ident(); + + match &field.storage_type { + StorageType::Direct => generate_count_arm_direct(field, variant), + StorageType::AutoSet => generate_count_arm_set(field, variant), + StorageType::CounterMap | StorageType::AutoMap => generate_count_arm_map(field, variant), + StorageType::Flag => generate_count_arm_flag(field, variant), + } +} + +fn generate_count_arm_direct(field: &FieldInfo, variant: &Ident) -> proc_macro2::TokenStream { + let get_name = field.get_ident(); + quote! { + CachedDataItemType::#variant => if self.#get_name().is_some() { 1 } else { 0 }, + } +} + +fn generate_count_arm_set(field: &FieldInfo, variant: &Ident) -> proc_macro2::TokenStream { + let field_name = &field.field_name; + if field.is_inline() { + quote! { + CachedDataItemType::#variant => self.#field_name().len(), + } + } else { + quote! { + CachedDataItemType::#variant => self.#field_name().map(|s| s.len()).unwrap_or(0), + } + } +} + +fn generate_count_arm_map(field: &FieldInfo, variant: &Ident) -> proc_macro2::TokenStream { + let field_name = &field.field_name; + if field.is_inline() { + quote! { + CachedDataItemType::#variant => self.#field_name().len(), + } + } else { + quote! { + CachedDataItemType::#variant => self.#field_name().map(|m| m.len()).unwrap_or(0), + } + } +} + +fn generate_count_arm_flag(field: &FieldInfo, variant: &Ident) -> proc_macro2::TokenStream { + let field_name = &field.field_name; + quote! { + CachedDataItemType::#variant => if self.typed().flags.#field_name() { 1 } else { 0 }, + } +} + +/// Generate iter match arms for all fields with variants. +fn generate_iter_arms(grouped_fields: &GroupedFields) -> proc_macro2::TokenStream { + let arms: Vec<_> = grouped_fields + .fields_with_variant() + .map(generate_iter_arm) + .collect(); + + quote! { #(#arms)* } +} + +/// Generate a single iter match arm for a field. +fn generate_iter_arm(field: &FieldInfo) -> proc_macro2::TokenStream { + let variant = field.cached_data_variant_ident(); + + match &field.storage_type { + StorageType::Direct => generate_iter_arm_direct(field, variant), + StorageType::AutoSet => generate_iter_arm_set(field, variant), + StorageType::CounterMap | StorageType::AutoMap => generate_iter_arm_map(field, variant), + StorageType::Flag => generate_iter_arm_flag(field, variant), + } +} + +fn generate_iter_arm_direct(field: &FieldInfo, variant: &Ident) -> proc_macro2::TokenStream { + let get_name = field.get_ident(); + quote! { + CachedDataItemType::#variant => Box::new( + self.#get_name() + .into_iter() + .map(|value| (CachedDataItemKey::#variant {}, CachedDataItemValueRef::#variant { value })), + ), + } +} + +fn generate_iter_arm_set(field: &FieldInfo, variant: &Ident) -> proc_macro2::TokenStream { + let field_name = &field.field_name; + let key_expr = field.key_expr(); + let key_construction = field.key_construction(); + + if field.is_inline() { + quote! { + CachedDataItemType::#variant => Box::new(self.#field_name().iter().map(|#key_expr| { + ( + CachedDataItemKey::#variant { #key_construction }, + CachedDataItemValueRef::#variant { value: &() }, + ) + })), + } + } else { + quote! { + CachedDataItemType::#variant => Box::new( + self.#field_name() + .into_iter() + .flat_map(|set| set.iter()) + .map(|#key_expr| { + ( + CachedDataItemKey::#variant { #key_construction }, + CachedDataItemValueRef::#variant { value: &() }, + ) + }), + ), + } + } +} + +fn generate_iter_arm_map(field: &FieldInfo, variant: &Ident) -> proc_macro2::TokenStream { + let field_name = &field.field_name; + let key_expr = field.key_expr(); + let key_construction = field.key_construction(); + + if field.is_inline() { + quote! { + CachedDataItemType::#variant => Box::new(self.#field_name().iter().map(|(#key_expr, value)| { + ( + CachedDataItemKey::#variant { #key_construction }, + CachedDataItemValueRef::#variant { value }, + ) + })), + } + } else { + quote! { + CachedDataItemType::#variant => Box::new( + self.#field_name() + .into_iter() + .flat_map(|m| m.iter()) + .map(|(#key_expr, value)| { + ( + CachedDataItemKey::#variant { #key_construction }, + CachedDataItemValueRef::#variant { value }, + ) + }), + ), + } + } +} + +fn generate_iter_arm_flag(field: &FieldInfo, variant: &Ident) -> proc_macro2::TokenStream { + let field_name = &field.field_name; + quote! { + CachedDataItemType::#variant => Box::new( + self.typed() + .flags + .#field_name() + .then_some(( + CachedDataItemKey::#variant {}, + CachedDataItemValueRef::#variant { value: &() }, + )) + .into_iter(), + ), + } +} + +// ============================================================================= +// Optimized add() match arms +// ============================================================================= + +/// Generate add match arms for all fields with variants. +/// Delegates to typed methods for single check_access + conditional track_modification. +fn generate_add_arms(grouped_fields: &GroupedFields) -> proc_macro2::TokenStream { + let arms: Vec<_> = grouped_fields + .fields_with_variant() + .map(generate_add_arm) + .collect(); + + quote! { #(#arms)* } +} + +fn generate_add_arm(field: &FieldInfo) -> proc_macro2::TokenStream { + let variant = field.cached_data_variant_ident(); + + match &field.storage_type { + StorageType::Direct => generate_add_arm_direct(field, variant), + StorageType::AutoSet => generate_add_arm_auto_set(field, variant), + StorageType::CounterMap | StorageType::AutoMap => generate_add_arm_map(field, variant), + StorageType::Flag => generate_add_arm_flag(field, variant), + } +} + +fn generate_add_arm_direct(field: &FieldInfo, variant: &Ident) -> proc_macro2::TokenStream { + let has_name = field.has_ident(); + let set_name = field.set_ident(); + quote! { + ( + CachedDataItemKey::#variant {}, + CachedDataItemValue::#variant { value }, + ) => { + if self.#has_name() { + false + } else { + self.#set_name(value); + true + } + }, + } +} + +fn generate_add_arm_auto_set(field: &FieldInfo, variant: &Ident) -> proc_macro2::TokenStream { + let add_name = field.prefixed_ident("add"); + let key_pattern = field.key_pattern(); + let key_expr = field.key_expr(); + quote! { + ( + CachedDataItemKey::#variant { #key_pattern }, + CachedDataItemValue::#variant { value: () }, + ) => self.#add_name(#key_expr), + } +} + +fn generate_add_arm_map(field: &FieldInfo, variant: &Ident) -> proc_macro2::TokenStream { + let field_name = &field.field_name; + let field_mut = field.mut_ident(); + let key_pattern = field.key_pattern(); + let key_expr = field.key_expr(); + + if field.is_inline() { + quote! { + ( + CachedDataItemKey::#variant { #key_pattern }, + CachedDataItemValue::#variant { value }, + ) => { + if self.#field_name().get(&#key_expr).is_some() { + false + } else { + self.#field_mut().insert(#key_expr, value); + true + } + }, + } + } else { + quote! { + ( + CachedDataItemKey::#variant { #key_pattern }, + CachedDataItemValue::#variant { value }, + ) => { + if self.#field_name().is_some_and(|m| m.get(&#key_expr).is_some()) { + false + } else { + self.#field_mut().insert(#key_expr, value); + true + } + }, + } + } +} + +fn generate_add_arm_flag(field: &FieldInfo, variant: &Ident) -> proc_macro2::TokenStream { + let field_name = &field.field_name; + let set_name = field.set_ident(); + quote! { + ( + CachedDataItemKey::#variant {}, + CachedDataItemValue::#variant { value: () }, + ) => { + if self.typed().flags.#field_name() { + false + } else { + self.typed_mut().flags.#set_name(true); + true + } + }, + } +} + +// ============================================================================= +// Optimized extend() match arms +// ============================================================================= + +/// Generate extend match arms for all fields with variants. +/// Uses typed batch methods for single check_access + single track_modification. +fn generate_extend_arms(grouped_fields: &GroupedFields) -> proc_macro2::TokenStream { + let arms: Vec<_> = grouped_fields + .fields_with_variant() + .map(generate_extend_arm) + .collect(); + + quote! { #(#arms)* } +} + +fn generate_extend_arm(field: &FieldInfo) -> proc_macro2::TokenStream { + let variant = field.cached_data_variant_ident(); + + match &field.storage_type { + StorageType::Direct => generate_extend_arm_direct(field, variant), + StorageType::AutoSet => generate_extend_arm_auto_set(field, variant), + StorageType::CounterMap | StorageType::AutoMap => generate_extend_arm_map(field, variant), + StorageType::Flag => generate_extend_arm_flag(field, variant), + } +} + +fn generate_extend_arm_direct(_field: &FieldInfo, variant: &Ident) -> proc_macro2::TokenStream { + // Direct fields can only have one value, so just delegate to add() for the first item + quote! { + CachedDataItemType::#variant => { + for item in items { + return self.add(item); + } + true + }, + } +} + +fn generate_extend_arm_auto_set(field: &FieldInfo, variant: &Ident) -> proc_macro2::TokenStream { + let extend_name = field.suffixed_ident("extend"); + let key_pattern = field.key_pattern(); + let key_expr = field.key_expr(); + quote! { + CachedDataItemType::#variant => { + // Delegate to typed extend method which batches check_access + track_modification + self.#extend_name(items.into_iter().filter_map(|item| { + match item.into_key_and_value() { + (CachedDataItemKey::#variant { #key_pattern }, _) => Some(#key_expr), + _ => None, + } + })); + true // AutoSet extend doesn't track per-item success + }, + } +} + +fn generate_extend_arm_map(field: &FieldInfo, variant: &Ident) -> proc_macro2::TokenStream { + let field_mut = field.mut_ident(); + let key_pattern = field.key_pattern(); + let key_expr = field.key_expr(); + quote! { + CachedDataItemType::#variant => { + let mut all_new = true; + // Get mutable reference once (single check_access + track_modification) + let map = self.#field_mut(); + for item in items { + if let (CachedDataItemKey::#variant { #key_pattern }, CachedDataItemValue::#variant { value }) + = item.into_key_and_value() + { + if map.insert(#key_expr, value).is_some() { + all_new = false; + } + } + } + all_new + }, + } +} + +fn generate_extend_arm_flag(_field: &FieldInfo, variant: &Ident) -> proc_macro2::TokenStream { + // Flags can only have one value, so just delegate to add() for the first item + quote! { + CachedDataItemType::#variant => { + for item in items { + return self.add(item); + } + true + }, + } +} + +// ============================================================================= +// Optimized extract_if() match arms +// ============================================================================= + +/// Generate extract_if match arms for all fields with variants. +/// Uses retain pattern for single check_access + single track_modification. +fn generate_extract_if_arms(grouped_fields: &GroupedFields) -> proc_macro2::TokenStream { + let arms: Vec<_> = grouped_fields + .fields_with_variant() + .map(generate_extract_if_arm) + .collect(); + + quote! { #(#arms)* } +} + +fn generate_extract_if_arm(field: &FieldInfo) -> proc_macro2::TokenStream { + let variant = field.cached_data_variant_ident(); + + match &field.storage_type { + StorageType::Direct => generate_extract_if_arm_direct(field, variant), + StorageType::AutoSet => generate_extract_if_arm_auto_set(field, variant), + StorageType::CounterMap | StorageType::AutoMap => { + generate_extract_if_arm_map(field, variant) + } + StorageType::Flag => generate_extract_if_arm_flag(field, variant), + } +} + +fn generate_extract_if_arm_direct(field: &FieldInfo, variant: &Ident) -> proc_macro2::TokenStream { + let take_name = field.take_ident(); + let get_name = field.get_ident(); + quote! { + CachedDataItemType::#variant => { + let key = CachedDataItemKey::#variant {}; + if let Some(value_ref) = self.#get_name() { + if predicate(key.clone(), CachedDataItemValueRef::#variant { value: value_ref }) { + if let Some(value) = self.#take_name() { + return vec![CachedDataItem::from_key_and_value(key, CachedDataItemValue::#variant { value })]; + } + } + } + Vec::new() + }, + } +} + +fn generate_extract_if_arm_auto_set( + field: &FieldInfo, + variant: &Ident, +) -> proc_macro2::TokenStream { + let field_name = &field.field_name; + let key_expr = field.key_expr(); + let key_construction = field.key_construction(); + + // AutoSet doesn't have retain, so we collect keys first and then remove them. + // The typed iter_X and remove_X methods handle check_access/track_modification efficiently. + if field.is_inline() { + quote! { + CachedDataItemType::#variant => { + // First pass: collect keys to remove (single check_access via iter) + let keys_to_remove: Vec<_> = self.#field_name().iter().filter_map(|#key_expr| { + let key = CachedDataItemKey::#variant { #key_construction }; + let value_ref = CachedDataItemValueRef::#variant { value: &() }; + if predicate(key.clone(), value_ref) { + Some(key) + } else { + None + } + }).collect(); + + // Second pass: remove items using the adapter's remove method + keys_to_remove.into_iter().filter_map(|key| { + self.remove(&key).map(|value| { + CachedDataItem::from_key_and_value(key, value) + }) + }).collect() + }, + } + } else { + // Lazy autoset iter methods return owned values (via .copied()), so use + // key_construction_owned + let iter_name = field.iter_ident(); + let key_construction_owned = field.key_construction_owned(); + quote! { + CachedDataItemType::#variant => { + // First pass: collect keys to remove (single check_access via iter) + let keys_to_remove: Vec<_> = self.#iter_name().filter_map(|#key_expr| { + let key = CachedDataItemKey::#variant { #key_construction_owned }; + let value_ref = CachedDataItemValueRef::#variant { value: &() }; + if predicate(key.clone(), value_ref) { + Some(key) + } else { + None + } + }).collect(); + + // Second pass: remove items using the adapter's remove method + keys_to_remove.into_iter().filter_map(|key| { + self.remove(&key).map(|value| { + CachedDataItem::from_key_and_value(key, value) + }) + }).collect() + }, + } + } +} + +fn generate_extract_if_arm_map(field: &FieldInfo, variant: &Ident) -> proc_macro2::TokenStream { + let field_name = &field.field_name; + let key_expr = field.key_expr(); + let key_construction = field.key_construction(); + + // Maps (CounterMap/AutoMap) don't have retain with the signature we need, + // so we collect keys first and then remove them. + // Use the adapter's remove method which handles track_modification. + if field.is_inline() { + quote! { + CachedDataItemType::#variant => { + // First pass: collect keys to remove + let keys_to_remove: Vec<_> = self.#field_name().iter().filter_map(|(#key_expr, value)| { + let key = CachedDataItemKey::#variant { #key_construction }; + let value_ref = CachedDataItemValueRef::#variant { value }; + if predicate(key.clone(), value_ref) { + Some(key) + } else { + None + } + }).collect(); + + // Second pass: remove and collect using the adapter's remove method + keys_to_remove.into_iter().filter_map(|key| { + self.remove(&key).map(|value| { + CachedDataItem::from_key_and_value(key, value) + }) + }).collect() + }, + } + } else { + // For lazy map fields, use iter_X_entries which iterates over (key, value) pairs + let iter_entries_name = field.infixed_ident("iter", "entries"); + quote! { + CachedDataItemType::#variant => { + // First pass: collect keys to remove + let keys_to_remove: Vec<_> = self.#iter_entries_name().filter_map(|(#key_expr, value)| { + let key = CachedDataItemKey::#variant { #key_construction }; + let value_ref = CachedDataItemValueRef::#variant { value }; + if predicate(key.clone(), value_ref) { + Some(key) + } else { + None + } + }).collect(); + + // Second pass: remove and collect using the adapter's remove method + keys_to_remove.into_iter().filter_map(|key| { + self.remove(&key).map(|value| { + CachedDataItem::from_key_and_value(key, value) + }) + }).collect() + }, + } + } +} + +fn generate_extract_if_arm_flag(field: &FieldInfo, variant: &Ident) -> proc_macro2::TokenStream { + let field_name = &field.field_name; + let set_name = field.set_ident(); + quote! { + CachedDataItemType::#variant => { + let key = CachedDataItemKey::#variant {}; + if self.typed().flags.#field_name() { + let value_ref = CachedDataItemValueRef::#variant { value: &() }; + if predicate(key.clone(), value_ref) { + self.typed_mut().flags.#set_name(false); + return vec![CachedDataItem::from_key_and_value(key, CachedDataItemValue::#variant { value: () })]; + } + } + Vec::new() + }, + } +} diff --git a/turbopack/crates/turbo-tasks/src/priority_runner.rs b/turbopack/crates/turbo-tasks/src/priority_runner.rs index ce4eed37397cb5..8d5e2ad70cf8d6 100644 --- a/turbopack/crates/turbo-tasks/src/priority_runner.rs +++ b/turbopack/crates/turbo-tasks/src/priority_runner.rs @@ -389,7 +389,11 @@ impl Future for JoinHandle { #[cfg(test)] mod tests { - use std::{sync::Arc, thread::sleep, time::Duration}; + use std::{ + sync::{Arc, Barrier}, + thread::sleep, + time::Duration, + }; use super::*; @@ -542,6 +546,13 @@ mod tests { assert_eq!(*results, vec![0, 1, 2, 3, 4, 5, 6, 7, 8, 9]); } + /// Test that verifies priority ordering with mixed CPU-bound and waiting tasks. + /// + /// - Tasks 0-9 are CPU-bound (simulated using a non-tokio barrier) + /// - Tasks 10-19 are waiting tasks (async yield) + /// + /// Each task waits on two barriers (start, finish). The release sequence + /// controls execution order deterministically. #[test] fn test_mixed_cpu_bound_and_waiting_tasks() { tokio::runtime::Builder::new_multi_thread() @@ -552,85 +563,204 @@ mod tests { .enable_all() .build() .unwrap() - .block_on(test_mixed_cpu_bound_and_waiting_tasks_impl()); + .block_on(async { + tokio::time::timeout( + Duration::from_secs(10), + test_mixed_cpu_bound_and_waiting_tasks_impl(), + ) + .await + }) + .expect("Timed out") } async fn test_mixed_cpu_bound_and_waiting_tasks_impl() { + const NUM_TASKS: usize = 20; + + struct TestContext { + dispatch_order: Mutex>, + completion_order: Mutex>, + task_barriers: Vec<(Barrier, Barrier)>, + } + + impl Drop for TestContext { + fn drop(&mut self) { + // Print ordering for debugging purposes (in both test success + // and failure cases). Not asserted because the barriers will + // enforce a reasonable ordering and there's a bit of a race + // between barrier release and printing anyways. + let dispatch_order = self.dispatch_order.lock().clone(); + let completion_order = self.completion_order.lock().clone(); + println!("Dispatch order: {:?}", dispatch_order); + println!("Completion order: {:?}", completion_order); + } + } + struct ExecutorImpl; - impl Executor>, u32, u32> for ExecutorImpl { + impl Executor for ExecutorImpl { type Future = Pin + Send>>; fn execute( &self, - execute_context: &Arc>>, - task: u32, + ctx: &Arc, + (task, cpu): (u32, bool), _priority: u32, ) -> Self::Future { - let execute_context = execute_context.clone(); - println!("Created task {}", task); + let ctx = ctx.clone(); Box::pin(async move { - let cpu_bound = task < 50; - if cpu_bound { - println!("Executing cpu-bound task {}...", task); - // CPU bound task - sleep(Duration::from_millis((task as u64 + 1) * 10)); - } else { - println!("Executing waiting task {}...", task); - // Waiting task - tokio::time::sleep(Duration::from_millis((task as u64 + 1) * 10)).await; - } - execute_context.lock().push(task); - if cpu_bound { - println!("Finished cpu-bound task {}.", task); - } else { - println!("Finished waiting task {}.", task); + println!("Dispatched task {task}"); + ctx.dispatch_order.lock().push(task); + let ctx_clone = ctx.clone(); + tokio::task::spawn_blocking(move || { + ctx_clone.task_barriers[task as usize].0.wait(); + }) + .await + .unwrap(); + println!("Started task {task}"); + if !cpu { + tokio::task::yield_now().await; } + // The ending barrier is sync! + ctx.task_barriers[task as usize].1.wait(); + println!("Finished task {task}"); + ctx.completion_order.lock().push(task); }) } } - let executor = ExecutorImpl; + let ctx = Arc::new(TestContext { + dispatch_order: Mutex::new(Vec::new()), + completion_order: Mutex::new(Vec::new()), + task_barriers: (0..NUM_TASKS) + .map(|_| (Barrier::new(2), Barrier::new(2))) + .collect(), + }); - let runner: Arc>, u32, u32, _>> = - Arc::new(PriorityRunner::new(executor)); - let results = Arc::new(Mutex::new(Vec::new())); + let runner = Arc::new(PriorityRunner::new(ExecutorImpl)); - for i in 0..100 { - let results = results.clone(); - println!("Scheduling task {}...", i); - runner.schedule(&results, i, i); + #[derive(Debug)] + enum Action { + Schedule(u32, bool), // true if cpu, false if wait + ScheduleStart(u32, bool), // true if cpu, false if wait + StartFinish(u32), + Start(u32), + Finish(u32), } - while results.lock().len() < 100 { + // This action sequence encodes scheduling and barrier-runs. + #[rustfmt::skip] + let actions: &[Action] = &[ + // Schedule and start 0 and 1 (CPU-bound). + Action::ScheduleStart(0, true), + Action::ScheduleStart(1, true), + + // These sneak in during a thread race + Action::Schedule(2, true), + Action::Schedule(3, true), + Action::Schedule(4, true), + Action::Schedule(5, true), + + // Let CPU-bound 0 and 1 reach complete which allows 4 and 5 to start + Action::Finish(0), + Action::Finish(1), + Action::Start(4), + Action::Start(5), + + // Schedule the rest of the tasks while the CPU-bound tasks are running + Action::Schedule(6, true), + Action::Schedule(7, true), + Action::Schedule(8, true), + Action::Schedule(9, true), + // 10..19 are waiting tasks + Action::Schedule(10, false), + Action::Schedule(11, false), + Action::Schedule(12, false), + Action::Schedule(13, false), + Action::Schedule(14, false), + Action::Schedule(15, false), + Action::Schedule(16, false), + Action::Schedule(17, false), + Action::Schedule(18, false), + Action::Schedule(19, false), + + // Let CPU-bound 2 and 3 reach complete which lets in the high priority tasks + Action::Finish(4), + Action::StartFinish(19), + Action::Finish(5), + Action::StartFinish(18), + + // Then let the rest of the waiting tasks through + Action::StartFinish(17), + Action::StartFinish(16), + Action::StartFinish(15), + Action::StartFinish(14), + Action::StartFinish(13), + Action::StartFinish(12), + Action::StartFinish(11), + Action::StartFinish(10), + + // And interleave the CPU ones a bit + Action::Start(9), + Action::Start(8), + Action::Finish(8), + Action::Start(7), + Action::Finish(7), + Action::Finish(9), + Action::Start(6), + Action::Finish(6), + Action::Start(3), + Action::Start(2), + Action::Finish(2), + Action::Finish(3), + ]; + + // Run in a blocking thread to avoid competing for workers + let ctx_clone = ctx.clone(); + tokio::task::spawn_blocking(move || { + let ctx = ctx_clone; + let mut scheduled = 0; + let mut started = 0; + let mut finished = 0; + for action in actions { + println!("{:?}", action); + match action { + Action::Schedule(task, cpu) => { + runner.schedule(&ctx, (*task, *cpu), *task); + scheduled += 1; + } + Action::ScheduleStart(task, cpu) => { + runner.schedule(&ctx, (*task, *cpu), *task); + ctx.task_barriers[*task as usize].0.wait(); + scheduled += 1; + started += 1; + } + Action::StartFinish(task) => { + ctx.task_barriers[*task as usize].0.wait(); + started += 1; + ctx.task_barriers[*task as usize].1.wait(); + finished += 1; + } + Action::Start(task) => { + ctx.task_barriers[*task as usize].0.wait(); + started += 1; + } + Action::Finish(task) => { + ctx.task_barriers[*task as usize].1.wait(); + finished += 1; + } + } + } + + assert_eq!(scheduled, NUM_TASKS); + assert_eq!(started, NUM_TASKS); + assert_eq!(finished, NUM_TASKS); + }) + .await + .unwrap(); + + println!("Waiting for completion..."); + while ctx.completion_order.lock().len() < NUM_TASKS { tokio::time::sleep(Duration::from_millis(10)).await; } - let results = results.lock(); - println!("Results: {:?}", *results); - - // The first two tasks are directly spawned without queuing - assert_eq!(&results[0..2], &[0, 1]); - // All tasks after that are queued and therefore prioritized - // The waiting tasks are just waiting, so all of them are executed. - // And the two highest priority cpu-bound tasks are executed too. - // Since we only have 2 workers, the waiting tasks ain't polled until the cpu-bound tasks - // are done. - assert!(results[2..4].contains(&49)); - assert!(results[2..4].contains(&48)); - let waiting_task_pos = results - .iter() - .position(|&x| x >= 50) - .expect("Waiting task should be executed"); - // Waiting tasks should be interleaved with cpu-bound tasks - assert!(waiting_task_pos < 45); - - let cpu_bound_results = results - .iter() - .copied() - .filter(|&x| x < 50) - .collect::>(); - // The last tasks are the tasks with the lowest priority - assert!(cpu_bound_results[48..50].contains(&2)); - assert!(cpu_bound_results[48..50].contains(&3)); } }