diff --git a/eslint.config.mjs b/eslint.config.mjs index 302bcec4d3a74..49c513913cf76 100644 --- a/eslint.config.mjs +++ b/eslint.config.mjs @@ -294,7 +294,7 @@ export default defineConfig( languageOptions: { parserOptions: { tsconfigRootDir: dirname, - project: ['./tsconfig.json'], + projectService: true, }, }, }, @@ -335,6 +335,32 @@ export default defineConfig( }, }, + // Catch leaked subscriptions: call statements whose returned cleanup / + // unsubscribe function is discarded. Type-aware, so it needs TypeScript type + // information (same `projectService` setup as `mui-x/no-direct-state-access` above). + { + files: [`packages/*/src/**/*${EXTENSION_TS}`], + ignores: [ + '**/*.d.ts', + `**/*.spec${EXTENSION_TS}`, + `**/*.test${EXTENSION_TS}`, + // Codemods are jscodeshift AST transforms with no runtime subscriptions; + // the only hits are chai assertions in a test-style file. + 'packages/x-codemod/**', + // Vendored copy of Base UI internals — keep in sync with upstream, don't edit. + 'packages/x-scheduler-internals/src/base-ui-copy/**', + ], + languageOptions: { + parserOptions: { + tsconfigRootDir: dirname, + projectService: true, + }, + }, + rules: { + 'mui/no-floating-cleanup': 'error', + }, + }, + // Common config from core start { files: [`docs/**/*${EXTENSION_TS}`], diff --git a/package.json b/package.json index 4b134643cbd64..e5ebd094b40bc 100644 --- a/package.json +++ b/package.json @@ -77,7 +77,7 @@ "@mui/internal-babel-plugin-display-name": "1.0.4-canary.20", "@mui/internal-babel-plugin-minify-errors": "2.0.8-canary.27", "@mui/internal-bundle-size-checker": "1.0.9-canary.81", - "@mui/internal-code-infra": "0.0.4-canary.64", + "@mui/internal-code-infra": "0.0.4-canary.66", "@mui/internal-api-docs-builder": "1.0.2-canary.2", "@mui/internal-markdown": "3.0.9-canary.2", "@mui/internal-netlify-cache": "0.0.3-canary.5", diff --git a/packages/x-charts/src/internals/scales/scaleBand.ts b/packages/x-charts/src/internals/scales/scaleBand.ts index 6953f8d2907d5..f9cdb6b21b056 100644 --- a/packages/x-charts/src/internals/scales/scaleBand.ts +++ b/packages/x-charts/src/internals/scales/scaleBand.ts @@ -169,7 +169,9 @@ function createScaleBand(seed?: ScaleBandState): ScaleBand { scale.copy = () => createScaleBand({ index, domain, r0, r1, isRound, paddingInner, paddingOuter, align }); - rescale(); + // `rescale` returns the scale for the fluent setters; here it only seeds the + // initial layout, so the (callable) return is intentionally discarded. + void rescale(); return scale as any; } diff --git a/packages/x-chat/src/ChatBox/ChatBox.tsx b/packages/x-chat/src/ChatBox/ChatBox.tsx index c2baa83d0c2ef..20ec7f74935d7 100644 --- a/packages/x-chat/src/ChatBox/ChatBox.tsx +++ b/packages/x-chat/src/ChatBox/ChatBox.tsx @@ -113,7 +113,8 @@ const ChatBox = React.forwardRef(function ChatBox( (node: HTMLDivElement | null) => { setRootElement(node); if (typeof ref === 'function') { - ref(node); + // Legacy callback-ref forwarding; a React 19 cleanup return is not propagated here. + void ref(node); } else if (ref) { (ref as React.MutableRefObject).current = node; } diff --git a/packages/x-chat/src/ChatBox/ChatBoxContent.tsx b/packages/x-chat/src/ChatBox/ChatBoxContent.tsx index 8d18d1fc94709..7b4de62613f70 100644 --- a/packages/x-chat/src/ChatBox/ChatBoxContent.tsx +++ b/packages/x-chat/src/ChatBox/ChatBoxContent.tsx @@ -206,7 +206,8 @@ const ChatBoxConversationOverlay = styled('div', { // conversations pane. Marking it keeps ChatLayout's pane resolution unambiguous — // once any sibling (the thread view) is marked, every direct child must be marked // or ChatLayout warns about a mixed/undeterminable set. -markChatLayoutPane(ChatBoxConversationOverlay, 'conversations'); +// `markChatLayoutPane` mutates the component in place and returns it; the return is discarded here. +void markChatLayoutPane(ChatBoxConversationOverlay, 'conversations'); const ChatBoxConversationOverlayBackdrop = styled('div', { name: 'MuiChatBox', @@ -632,7 +633,7 @@ function createMarkedConversationListComponent( return ; }, ); - markChatLayoutPane(MarkedConversationList, 'conversations'); + void markChatLayoutPane(MarkedConversationList, 'conversations'); return MarkedConversationList as typeof ChatConversationList; } diff --git a/packages/x-chat/src/ChatConversation/ChatConversation.tsx b/packages/x-chat/src/ChatConversation/ChatConversation.tsx index 6456696a4c58d..0981293ceb951 100644 --- a/packages/x-chat/src/ChatConversation/ChatConversation.tsx +++ b/packages/x-chat/src/ChatConversation/ChatConversation.tsx @@ -85,6 +85,8 @@ ChatConversation.propTypes /* remove-proptypes */ = { // Mirror the headless `ConversationRoot` pane marker on the Material wrapper so // `ChatLayout` assigns it to the thread pane (the symbol lives on the headless // primitive, not this wrapper). -markChatLayoutPane(ChatConversation, 'thread'); +// `markChatLayoutPane` mutates the component in place and returns it for the +// `const X = markChatLayoutPane(...)` form; here the return is intentionally discarded. +void markChatLayoutPane(ChatConversation, 'thread'); export { ChatConversation }; diff --git a/packages/x-chat/src/ChatConversationList/ChatConversationList.tsx b/packages/x-chat/src/ChatConversationList/ChatConversationList.tsx index 62b1fbc5f4e4f..0bdfe493c6a61 100644 --- a/packages/x-chat/src/ChatConversationList/ChatConversationList.tsx +++ b/packages/x-chat/src/ChatConversationList/ChatConversationList.tsx @@ -820,6 +820,7 @@ ChatConversationList.propTypes /* remove-proptypes */ = { // primitive, not this wrapper). Without it, a split layout with the list visible and // no active conversation — a single unmarked child — falls back to the thread pane, // skipping the `conversationsPane` slot/styles. -markChatLayoutPane(ChatConversationList, 'conversations'); +// `markChatLayoutPane` mutates the component in place and returns it; the return is discarded here. +void markChatLayoutPane(ChatConversationList, 'conversations'); export { ChatConversationList }; diff --git a/packages/x-chat/src/internals/mergeSlotProps.ts b/packages/x-chat/src/internals/mergeSlotProps.ts index a9f9b57f4ee10..7f1d104a2304e 100644 --- a/packages/x-chat/src/internals/mergeSlotProps.ts +++ b/packages/x-chat/src/internals/mergeSlotProps.ts @@ -17,7 +17,8 @@ function setRef(ref: React.Ref, value: unknown) { return; } if (typeof ref === 'function') { - ref(value); + // Legacy callback-ref forwarding; a React 19 cleanup return is not propagated here. + void ref(value); return; } diff --git a/packages/x-data-grid-premium/src/hooks/utils/useKeepGroupedColumnsHidden.ts b/packages/x-data-grid-premium/src/hooks/utils/useKeepGroupedColumnsHidden.ts index db1cf74d34fb4..9cd31247a4192 100644 --- a/packages/x-data-grid-premium/src/hooks/utils/useKeepGroupedColumnsHidden.ts +++ b/packages/x-data-grid-premium/src/hooks/utils/useKeepGroupedColumnsHidden.ts @@ -47,7 +47,7 @@ export const useKeepGroupedColumnsHidden = ( ); React.useEffect(() => { - props.apiRef.current?.subscribeEvent('rowGroupingModelChange', (newModel) => { + return props.apiRef.current?.subscribeEvent('rowGroupingModelChange', (newModel) => { const columnVisibilityModel = updateColumnVisibilityModel( gridColumnVisibilityModelSelector(props.apiRef), newModel, diff --git a/packages/x-data-grid/src/hooks/core/strategyProcessing/useGridRegisterStrategyProcessor.ts b/packages/x-data-grid/src/hooks/core/strategyProcessing/useGridRegisterStrategyProcessor.ts index 2b5deed922fa2..494bede0b871b 100644 --- a/packages/x-data-grid/src/hooks/core/strategyProcessing/useGridRegisterStrategyProcessor.ts +++ b/packages/x-data-grid/src/hooks/core/strategyProcessing/useGridRegisterStrategyProcessor.ts @@ -15,7 +15,13 @@ export const useGridRegisterStrategyProcessor = < processor: GridStrategyProcessor, ) => { const registerPreProcessor = React.useCallback(() => { - apiRef.current.registerStrategyProcessor(strategyName, group, processor); + // NOTE: the unregister fn is intentionally discarded. Unlike pipe processors + // (which are additive), a strategy processor is required for as long as its + // strategy is active — `applyStrategyProcessor` throws if the active strategy's + // processor is missing — so it must outlive the registering component. The cache + // keeps a single entry per (processor, strategy) and is reclaimed with the grid + // api, so nothing leaks; `void` documents the deliberate discard. + void apiRef.current.registerStrategyProcessor(strategyName, group, processor); }, [apiRef, processor, group, strategyName]); useFirstRender(() => { diff --git a/packages/x-data-grid/src/hooks/features/rowSelection/useGridRowSelection.ts b/packages/x-data-grid/src/hooks/features/rowSelection/useGridRowSelection.ts index 96e15fb547100..bb6d87b140c33 100644 --- a/packages/x-data-grid/src/hooks/features/rowSelection/useGridRowSelection.ts +++ b/packages/x-data-grid/src/hooks/features/rowSelection/useGridRowSelection.ts @@ -960,10 +960,6 @@ You need to upgrade to DataGridPro or DataGridPremium component to unlock multip } }, [apiRef, canHaveMultipleSelection, checkboxSelection, isStateControlled, props.rowSelection]); - React.useEffect(() => { - runIf(props.rowSelection, removeOutdatedSelection); - }, [props.rowSelection, removeOutdatedSelection]); - React.useEffect(() => { if (isFirstRender.current) { isFirstRender.current = false; diff --git a/packages/x-scheduler-internals-premium/src/use-event-timeline-premium/EventTimelinePremiumStore.ts b/packages/x-scheduler-internals-premium/src/use-event-timeline-premium/EventTimelinePremiumStore.ts index 6f918d650f251..7700ae079c37a 100644 --- a/packages/x-scheduler-internals-premium/src/use-event-timeline-premium/EventTimelinePremiumStore.ts +++ b/packages/x-scheduler-internals-premium/src/use-event-timeline-premium/EventTimelinePremiumStore.ts @@ -140,10 +140,12 @@ export class EventTimelinePremiumStore< if (process.env.NODE_ENV !== 'production') { // Assert the initial state validity; `subscribe` only fires on subsequent state changes. this.assertPresetValidity(this.state.preset); - this.subscribe((state) => { - this.assertPresetValidity(state.preset); - return null; - }); + this.disposables.defer( + this.subscribe((state) => { + this.assertPresetValidity(state.preset); + return null; + }), + ); } this.lazyLoading = this.disposables.use(new EventTimelinePremiumLazyLoadingPlugin(this)); diff --git a/packages/x-scheduler-internals/src/use-event-calendar/EventCalendarStore.ts b/packages/x-scheduler-internals/src/use-event-calendar/EventCalendarStore.ts index b262dc403f5a5..7fac489eb1c1c 100644 --- a/packages/x-scheduler-internals/src/use-event-calendar/EventCalendarStore.ts +++ b/packages/x-scheduler-internals/src/use-event-calendar/EventCalendarStore.ts @@ -132,10 +132,12 @@ export class ExtendableEventCalendarStore< if (process.env.NODE_ENV !== 'production') { // Assert the initial state validity; `subscribe` only fires on subsequent state changes. this.assertViewValidity(this.state.view); - this.subscribe((state) => { - this.assertViewValidity(state.view); - return null; - }); + this.disposables.defer( + this.subscribe((state) => { + this.assertViewValidity(state.view); + return null; + }), + ); } } diff --git a/packages/x-scheduler/src/internals/components/more-events-popover/MoreEventsPopover.tsx b/packages/x-scheduler/src/internals/components/more-events-popover/MoreEventsPopover.tsx index f98e39db1f5d4..c3a6e5e623170 100644 --- a/packages/x-scheduler/src/internals/components/more-events-popover/MoreEventsPopover.tsx +++ b/packages/x-scheduler/src/internals/components/more-events-popover/MoreEventsPopover.tsx @@ -70,7 +70,7 @@ export default function MoreEventsPopoverContent(props: MoreEventsPopoverProps) const { subscribeCloseHandler } = useEventDialogContext(); React.useEffect(() => { - subscribeCloseHandler(() => { + return subscribeCloseHandler(() => { onClose(); }); }, [subscribeCloseHandler, onClose]); diff --git a/packages/x-tree-view-pro/src/internals/RichTreeViewProStore/RichTreeViewProStore.ts b/packages/x-tree-view-pro/src/internals/RichTreeViewProStore/RichTreeViewProStore.ts index 5beb295bcbb94..936b6fbf50f6e 100644 --- a/packages/x-tree-view-pro/src/internals/RichTreeViewProStore/RichTreeViewProStore.ts +++ b/packages/x-tree-view-pro/src/internals/RichTreeViewProStore/RichTreeViewProStore.ts @@ -18,9 +18,8 @@ export class RichTreeViewProStore< public itemsReordering = new TreeViewItemsReorderingPlugin(this); - public disposeEffect = () => { + public mountEffect = () => { this.lazyLoading.initEffect(); - return this.timeoutManager.clearAll; }; public constructor(parameters: RichTreeViewProStoreParameters) { diff --git a/packages/x-tree-view/src/internals/MinimalTreeViewStore/MinimalTreeViewStore.ts b/packages/x-tree-view/src/internals/MinimalTreeViewStore/MinimalTreeViewStore.ts index c4d81da7072ca..46bfff8a921c1 100644 --- a/packages/x-tree-view/src/internals/MinimalTreeViewStore/MinimalTreeViewStore.ts +++ b/packages/x-tree-view/src/internals/MinimalTreeViewStore/MinimalTreeViewStore.ts @@ -1,6 +1,11 @@ import { Store } from '@mui/x-internals/store'; import { warnOnce } from '@mui/x-internals/warning'; import { EventManager } from '@mui/x-internals/EventManager'; +import { + DisposableStack, + disposeSymbol, + unwrapSuppressedErrors, +} from '@mui/x-internals/disposable'; import { TreeViewModelUpdater, MinimalTreeViewParameters, @@ -40,13 +45,23 @@ export class MinimalTreeViewStore< private mapper: TreeViewParametersToStateMapper; - private eventManager = new EventManager(); + // Owns the store's teardown. Declared first so the resources below register + // against it during field initialization; disposed by `useDisposable` on + // unmount (see `[disposeSymbol]`). `public` so plugins can register their own + // subscriptions against it (hidden from the context store type). + public readonly disposables = new DisposableStack(); + + private eventManager = this.disposables.adopt(new EventManager(), (manager) => + manager.removeAllListeners(), + ); public instanceName: string; public parameters: Parameters; - public timeoutManager = new TimeoutManager(); + public timeoutManager = this.disposables.adopt(new TimeoutManager(), (manager) => + manager.clearAll(), + ); public itemPluginManager = new TreeViewItemPluginManager(); @@ -168,11 +183,32 @@ export class MinimalTreeViewStore< } /** - * Returns a cleanup function that need to be called when the store is destroyed. + * Runs mount-time side effects that must not happen during render (the store + * is created during render by `useDisposable`). No-op by default; overridden + * by stores that kick off work on mount (e.g. lazy-loading fetches). Safe to + * call more than once (StrictMode replays mount effects). */ - public disposeEffect = () => { - return this.timeoutManager.clearAll; - }; + public mountEffect = () => {}; + + /** + * Disposes the store synchronously when the component unmounts. `useDisposable` + * handles React StrictMode's simulated unmount, so this runs once on real unmount. + */ + [disposeSymbol](): void { + if (this.disposables.disposed) { + return; + } + try { + this.disposables.dispose(); + } catch (error) { + if (process.env.NODE_ENV !== 'production') { + console.error( + 'MUI X Tree View: error while disposing the store.', + ...unwrapSuppressedErrors(error), + ); + } + } + } /** * Whether updates based on `props.items` change should be ignored. @@ -190,13 +226,15 @@ export class MinimalTreeViewStore< ) => { let previousValue = selector(this.state); - this.subscribe((state) => { - const nextValue = selector(state); - if (nextValue !== previousValue) { - effect(previousValue, nextValue); - previousValue = nextValue; - } - }); + this.disposables.defer( + this.subscribe((state) => { + const nextValue = selector(state); + if (nextValue !== previousValue) { + effect(previousValue, nextValue); + previousValue = nextValue; + } + }), + ); }; /** diff --git a/packages/x-tree-view/src/internals/TreeViewProvider/TreeViewProvider.types.ts b/packages/x-tree-view/src/internals/TreeViewProvider/TreeViewProvider.types.ts index 88c3b6135a93d..87b963f7db4f9 100644 --- a/packages/x-tree-view/src/internals/TreeViewProvider/TreeViewProvider.types.ts +++ b/packages/x-tree-view/src/internals/TreeViewProvider/TreeViewProvider.types.ts @@ -1,4 +1,5 @@ import * as React from 'react'; +import { disposeSymbol } from '@mui/x-internals/disposable'; import { TreeItemWrapper, TreeViewItemPluginResponse, @@ -19,7 +20,9 @@ export type TreeViewStoreInContext = Omit< | 'update' | 'set' | 'updateStateFromParameters' - | 'disposeEffect' + | 'disposables' + | typeof disposeSymbol + | 'mountEffect' | 'registerStoreEffect' | 'itemPluginManager' | 'parameters' diff --git a/packages/x-tree-view/src/internals/hooks/useTreeViewStore.ts b/packages/x-tree-view/src/internals/hooks/useTreeViewStore.ts index 098e871d96a16..16311407bb87a 100644 --- a/packages/x-tree-view/src/internals/hooks/useTreeViewStore.ts +++ b/packages/x-tree-view/src/internals/hooks/useTreeViewStore.ts @@ -1,7 +1,7 @@ 'use client'; -import { useRefWithInit } from '@base-ui/utils/useRefWithInit'; import { useIsoLayoutEffect } from '@base-ui/utils/useIsoLayoutEffect'; import { useOnMount } from '@base-ui/utils/useOnMount'; +import { useDisposable } from '@mui/x-internals/useDisposable'; import { useRtl } from '@mui/system/RtlProvider'; import { TreeViewAnyStore } from '../models'; @@ -22,14 +22,16 @@ export function useTreeViewStore( parameters: UseTreeViewStoreParameters, ): TStore { const isRtl = useRtl(); - const store = useRefWithInit(() => new StoreClass({ ...parameters, isRtl })).current; + const store = useDisposable(() => new StoreClass({ ...parameters, isRtl })); useIsoLayoutEffect( () => store.updateStateFromParameters({ ...parameters, isRtl }), [store, isRtl, parameters], ); - useOnMount(store.disposeEffect); + // Mount-time side effects (e.g. kicking off lazy-loading fetches). The store is + // created during render by `useDisposable`, so these can't run in the factory. + useOnMount(store.mountEffect); return store; } diff --git a/packages/x-tree-view/src/internals/plugins/focus/TreeViewFocusPlugin.ts b/packages/x-tree-view/src/internals/plugins/focus/TreeViewFocusPlugin.ts index 668ca60abb545..3b677ccc6e6eb 100644 --- a/packages/x-tree-view/src/internals/plugins/focus/TreeViewFocusPlugin.ts +++ b/packages/x-tree-view/src/internals/plugins/focus/TreeViewFocusPlugin.ts @@ -20,35 +20,37 @@ export class TreeViewFocusPlugin { // Whenever the items change, we need to ensure the focused item is still present. // If the focused item was removed, focus the closest neighbor instead of the first item. let previousState = store.state; - this.store.subscribe((newState) => { - // Only run when items actually changed. - if (newState.itemMetaLookup === previousState.itemMetaLookup) { - previousState = newState; - return; - } + this.store.disposables.defer( + this.store.subscribe((newState) => { + // Only run when items actually changed. + if (newState.itemMetaLookup === previousState.itemMetaLookup) { + previousState = newState; + return; + } + + const focusedItemId = focusSelectors.focusedItemId(newState); + if (focusedItemId == null || itemsSelectors.itemMeta(newState, focusedItemId)) { + previousState = newState; + return; + } + + const checkItemInNewTree = (itemId: TreeViewItemId | null) => + itemId == null || !itemsSelectors.itemMeta(newState, itemId) ? null : itemId; + + const itemToFocusId = + checkItemInNewTree(getNextNavigableItem(previousState, focusedItemId)) ?? + checkItemInNewTree(getPreviousNavigableItem(previousState, focusedItemId)) ?? + getFirstNavigableItem(newState); + + if (itemToFocusId == null) { + this.setFocusedItemId(null); + } else { + this.applyItemFocus(null, itemToFocusId); + } - const focusedItemId = focusSelectors.focusedItemId(newState); - if (focusedItemId == null || itemsSelectors.itemMeta(newState, focusedItemId)) { previousState = newState; - return; - } - - const checkItemInNewTree = (itemId: TreeViewItemId | null) => - itemId == null || !itemsSelectors.itemMeta(newState, itemId) ? null : itemId; - - const itemToFocusId = - checkItemInNewTree(getNextNavigableItem(previousState, focusedItemId)) ?? - checkItemInNewTree(getPreviousNavigableItem(previousState, focusedItemId)) ?? - getFirstNavigableItem(newState); - - if (itemToFocusId == null) { - this.setFocusedItemId(null); - } else { - this.applyItemFocus(null, itemToFocusId); - } - - previousState = newState; - }); + }), + ); } private setFocusedItemId = (itemId: TreeViewItemId | null) => { diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index a3d51cad3077d..c60216aa60dc1 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -277,8 +277,8 @@ importers: specifier: 1.0.9-canary.81 version: 1.0.9-canary.81(@types/node@22.19.19)(esbuild@0.28.0)(jiti@2.7.0)(rolldown@1.0.3)(terser@5.48.0)(tsx@4.22.3)(yaml@2.9.0) '@mui/internal-code-infra': - specifier: 0.0.4-canary.64 - version: 0.0.4-canary.64(@next/eslint-plugin-next@16.2.6)(@types/node@22.19.19)(@typescript-eslint/eslint-plugin@8.61.0(@typescript-eslint/parser@8.61.0(eslint@10.4.1(jiti@2.7.0))(typescript@6.0.3))(eslint@10.4.1(jiti@2.7.0))(typescript@6.0.3))(@typescript-eslint/parser@8.61.0(eslint@10.4.1(jiti@2.7.0))(typescript@6.0.3))(eslint@10.4.1(jiti@2.7.0))(jest-diff@30.2.0)(postcss@8.5.15)(prettier@3.8.3)(stylelint@17.12.0(typescript@6.0.3))(typescript@6.0.3)(vitest@4.1.8) + specifier: 0.0.4-canary.66 + version: 0.0.4-canary.66(@next/eslint-plugin-next@16.2.6)(@types/node@22.19.19)(@typescript-eslint/eslint-plugin@8.61.0(@typescript-eslint/parser@8.61.0(eslint@10.4.1(jiti@2.7.0))(typescript@6.0.3))(eslint@10.4.1(jiti@2.7.0))(typescript@6.0.3))(@typescript-eslint/parser@8.61.0(eslint@10.4.1(jiti@2.7.0))(typescript@6.0.3))(eslint@10.4.1(jiti@2.7.0))(jest-diff@30.2.0)(postcss@8.5.15)(prettier@3.8.3)(stylelint@17.12.0(typescript@6.0.3))(typescript@6.0.3)(vitest@4.1.8) '@mui/internal-core-docs': specifier: 'catalog:' version: 9.0.2-canary.2(b296b1cdd39953f5604212bc0a0595d1) @@ -4276,8 +4276,8 @@ packages: resolution: {integrity: sha512-omgJCN/8RNOpO3FF0/ilW0PaImjDXeqDZStIGSaf6BEH1L7VwcXU7812ivHzMtTwLh8et/pq7q07j0j46B31JA==} hasBin: true - '@mui/internal-code-infra@0.0.4-canary.64': - resolution: {integrity: sha512-z/5cg2UA0BPwCMsF1WXJ1UOzyDvo0LwQPKm/DTf/pZtGcLlSg6vVWFQ8/mKIIMJ87TKH5YfKiNgZuC083idTNg==} + '@mui/internal-code-infra@0.0.4-canary.66': + resolution: {integrity: sha512-dPm/mwzVzCCeBexrVKtpdcDKWAQk5KW/eII7wl0mIqfq6lcZKPizUJuz57A3rmUUvXKh37UCbj38LbnlQtFrQg==} hasBin: true peerDependencies: '@next/eslint-plugin-next': '*' @@ -13339,7 +13339,7 @@ snapshots: - tsx - yaml - '@mui/internal-code-infra@0.0.4-canary.64(@next/eslint-plugin-next@16.2.6)(@types/node@22.19.19)(@typescript-eslint/eslint-plugin@8.61.0(@typescript-eslint/parser@8.61.0(eslint@10.4.1(jiti@2.7.0))(typescript@6.0.3))(eslint@10.4.1(jiti@2.7.0))(typescript@6.0.3))(@typescript-eslint/parser@8.61.0(eslint@10.4.1(jiti@2.7.0))(typescript@6.0.3))(eslint@10.4.1(jiti@2.7.0))(jest-diff@30.2.0)(postcss@8.5.15)(prettier@3.8.3)(stylelint@17.12.0(typescript@6.0.3))(typescript@6.0.3)(vitest@4.1.8)': + '@mui/internal-code-infra@0.0.4-canary.66(@next/eslint-plugin-next@16.2.6)(@types/node@22.19.19)(@typescript-eslint/eslint-plugin@8.61.0(@typescript-eslint/parser@8.61.0(eslint@10.4.1(jiti@2.7.0))(typescript@6.0.3))(eslint@10.4.1(jiti@2.7.0))(typescript@6.0.3))(@typescript-eslint/parser@8.61.0(eslint@10.4.1(jiti@2.7.0))(typescript@6.0.3))(eslint@10.4.1(jiti@2.7.0))(jest-diff@30.2.0)(postcss@8.5.15)(prettier@3.8.3)(stylelint@17.12.0(typescript@6.0.3))(typescript@6.0.3)(vitest@4.1.8)': dependencies: '@argos-ci/core': 6.0.1 '@babel/cli': 7.29.7(@babel/core@7.29.7)