diff --git a/.changeset/big-timers-relax.md b/.changeset/big-timers-relax.md deleted file mode 100644 index 651bcff90bb6..000000000000 --- a/.changeset/big-timers-relax.md +++ /dev/null @@ -1,6 +0,0 @@ ---- -'@rocket.chat/rest-typings': minor -'@rocket.chat/meteor': minor ---- - -Adds a new `contacts.checkExistence` endpoint, which allows identifying whether there's already a registered contact using a given email, phone, id or visitor to source association. diff --git a/.changeset/blue-items-raise.md b/.changeset/blue-items-raise.md deleted file mode 100644 index 7b5592a9efb2..000000000000 --- a/.changeset/blue-items-raise.md +++ /dev/null @@ -1,22 +0,0 @@ ---- -'@rocket.chat/fuselage-ui-kit': patch -'@rocket.chat/instance-status': patch -'@rocket.chat/ui-theming': patch -'@rocket.chat/model-typings': patch -'@rocket.chat/ui-video-conf': patch -'@rocket.chat/uikit-playground': patch -'@rocket.chat/core-typings': patch -'@rocket.chat/rest-typings': patch -'@rocket.chat/apps-engine': patch -'@rocket.chat/ui-composer': patch -'@rocket.chat/ui-contexts': patch -'@rocket.chat/gazzodown': patch -'@rocket.chat/ui-avatar': patch -'@rocket.chat/ui-client': patch -'@rocket.chat/livechat': patch -'@rocket.chat/ui-voip': patch -'@rocket.chat/i18n': patch -'@rocket.chat/meteor': patch ---- - -Fixes an error where the engine would not retry a subprocess restart if the last attempt failed diff --git a/.changeset/blue-rats-kick.md b/.changeset/blue-rats-kick.md deleted file mode 100644 index 16b0bbc97e21..000000000000 --- a/.changeset/blue-rats-kick.md +++ /dev/null @@ -1,6 +0,0 @@ ---- -"@rocket.chat/meteor": patch -"@rocket.chat/model-typings": patch ---- - -Fixes Unit's `numDepartments` property not being updated after a department is removed diff --git a/.changeset/chilled-seas-refuse.md b/.changeset/chilled-seas-refuse.md deleted file mode 100644 index d4066938513d..000000000000 --- a/.changeset/chilled-seas-refuse.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@rocket.chat/apps-engine': patch ---- - -Fixes the subprocess restarting routine failing to correctly restart apps in some cases diff --git a/.changeset/chilly-pants-hunt.md b/.changeset/chilly-pants-hunt.md deleted file mode 100644 index 0127ae7e174f..000000000000 --- a/.changeset/chilly-pants-hunt.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@rocket.chat/meteor": patch ---- - -Removes a validation that allowed only the room creator to propagate E2EE room keys. This was causing issues when the rooms were created via apps or some other integration, as the creator may not be online or able to create E2EE keys diff --git a/.changeset/clean-sloths-greet.md b/.changeset/clean-sloths-greet.md new file mode 100644 index 000000000000..ec821be29c65 --- /dev/null +++ b/.changeset/clean-sloths-greet.md @@ -0,0 +1,5 @@ +--- +"@rocket.chat/meteor": patch +--- + +Fixes the send attachments option not working on iOS browsers by moving it from the composer dropdown menu to the composer primary actions. diff --git a/.changeset/cold-mangos-impress.md b/.changeset/cold-mangos-impress.md deleted file mode 100644 index bd805577460a..000000000000 --- a/.changeset/cold-mangos-impress.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@rocket.chat/meteor': patch ---- - -Fixed an issue that caused clients to not properly receive certain server notifications right after login diff --git a/.changeset/cool-planes-protect.md b/.changeset/cool-planes-protect.md new file mode 100644 index 000000000000..f5b5a7fa665c --- /dev/null +++ b/.changeset/cool-planes-protect.md @@ -0,0 +1,22 @@ +--- +'@rocket.chat/omnichannel-transcript': patch +'@rocket.chat/authorization-service': patch +'@rocket.chat/stream-hub-service': patch +'@rocket.chat/presence-service': patch +'@rocket.chat/fuselage-ui-kit': patch +'@rocket.chat/account-service': patch +'@rocket.chat/mock-providers': patch +'@rocket.chat/ui-theming': patch +'@rocket.chat/uikit-playground': patch +'@rocket.chat/ddp-streamer': patch +'@rocket.chat/queue-worker': patch +'@rocket.chat/apps-engine': patch +'@rocket.chat/ui-composer': patch +'@rocket.chat/ui-contexts': patch +'@rocket.chat/ui-client': patch +'@rocket.chat/models': patch +'@rocket.chat/sha256': patch +'@rocket.chat/meteor': patch +--- + +Fixes an issue that prevented the apps-engine from reestablishing communications with subprocesses in some cases diff --git a/.changeset/curly-snails-walk.md b/.changeset/curly-snails-walk.md deleted file mode 100644 index 5033814ac634..000000000000 --- a/.changeset/curly-snails-walk.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@rocket.chat/meteor": patch ---- - -Fixes issue that caused the livechat appearance form not be able to submit on CE servers diff --git a/.changeset/empty-pans-love.md b/.changeset/empty-pans-love.md deleted file mode 100644 index a3ab8e26c8aa..000000000000 --- a/.changeset/empty-pans-love.md +++ /dev/null @@ -1,6 +0,0 @@ ---- -"@rocket.chat/meteor": patch -"@rocket.chat/i18n": patch ---- - -Fixes the incorrect registration status shown on admin users page for federated remote users. diff --git a/.changeset/fair-carrots-trade.md b/.changeset/fair-carrots-trade.md deleted file mode 100644 index 9c479c941ddf..000000000000 --- a/.changeset/fair-carrots-trade.md +++ /dev/null @@ -1,6 +0,0 @@ ---- -"@rocket.chat/meteor": patch -"@rocket.chat/model-typings": patch ---- - -Fixes "Average first response time" and "Best first response time" metrics being associated with the last agent who served the room (instead of the first one) diff --git a/.changeset/fifty-parrots-wonder.md b/.changeset/fifty-parrots-wonder.md deleted file mode 100644 index f0078cd51136..000000000000 --- a/.changeset/fifty-parrots-wonder.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@rocket.chat/meteor': patch ---- - -Fixes an issue preventing the creation of normal direct message rooms due to an invalid federation configuration, allowing proper room creation under standard settings. diff --git a/.changeset/five-peaches-approve.md b/.changeset/five-peaches-approve.md deleted file mode 100644 index 090e3716c025..000000000000 --- a/.changeset/five-peaches-approve.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@rocket.chat/meteor": patch ---- - -Adds support for `Use Full Name Initials to Generate Default Avatar` setting for the generated avatar preview button when editing an User's avatar diff --git a/.changeset/four-cows-sin.md b/.changeset/four-cows-sin.md deleted file mode 100644 index 27f3cd14c0cd..000000000000 --- a/.changeset/four-cows-sin.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@rocket.chat/meteor': patch ---- - -Fixes an issue where room members menu doesn't display properly without enough space diff --git a/.changeset/fuzzy-coins-lay.md b/.changeset/fuzzy-coins-lay.md deleted file mode 100644 index 5929829e41ab..000000000000 --- a/.changeset/fuzzy-coins-lay.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@rocket.chat/meteor': patch ---- - -Fixes missing images in Twitter article links to ensure proper display by relying on meta tags. diff --git a/.changeset/giant-bottles-impress.md b/.changeset/giant-bottles-impress.md new file mode 100644 index 000000000000..73015f544577 --- /dev/null +++ b/.changeset/giant-bottles-impress.md @@ -0,0 +1,6 @@ +--- +"@rocket.chat/meteor": patch +"@rocket.chat/core-typings": patch +--- + +Fixes an issue where the system would throw the error: 'GUI Application error' while uninstalling an app(when on the requests tab). diff --git a/.changeset/giant-nails-trade.md b/.changeset/giant-nails-trade.md deleted file mode 100644 index 76e92e999247..000000000000 --- a/.changeset/giant-nails-trade.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@rocket.chat/apps-engine': patch ---- - -Adds simple app subprocess metrics report diff --git a/.changeset/gold-comics-taste.md b/.changeset/gold-comics-taste.md deleted file mode 100644 index c9f864a0ffb5..000000000000 --- a/.changeset/gold-comics-taste.md +++ /dev/null @@ -1,22 +0,0 @@ ---- -'@rocket.chat/fuselage-ui-kit': patch -'@rocket.chat/instance-status': patch -'@rocket.chat/ui-theming': patch -'@rocket.chat/model-typings': patch -'@rocket.chat/ui-video-conf': patch -'@rocket.chat/uikit-playground': patch -'@rocket.chat/core-typings': patch -'@rocket.chat/rest-typings': patch -'@rocket.chat/apps-engine': patch -'@rocket.chat/ui-composer': patch -'@rocket.chat/ui-contexts': patch -'@rocket.chat/gazzodown': patch -'@rocket.chat/ui-avatar': patch -'@rocket.chat/ui-client': patch -'@rocket.chat/livechat': patch -'@rocket.chat/ui-voip': patch -'@rocket.chat/i18n': patch -'@rocket.chat/meteor': patch ---- - -Fixes error propagation when trying to get the status of apps in some cases diff --git a/.changeset/green-queens-end.md b/.changeset/green-queens-end.md deleted file mode 100644 index d6cf413bfcf6..000000000000 --- a/.changeset/green-queens-end.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@rocket.chat/meteor": patch ---- - -Fixes an issue with Federation startup where the bridge would intermittently fail to start causing error being shown "Matrix Bridge isn't running yet". diff --git a/.changeset/green-shirts-fold.md b/.changeset/green-shirts-fold.md deleted file mode 100644 index c4dc5cfcf3ad..000000000000 --- a/.changeset/green-shirts-fold.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@rocket.chat/meteor": patch ---- - -Fixes condition causing Omnichannel queue to start more than once. diff --git a/.changeset/honest-kings-allow.md b/.changeset/honest-kings-allow.md deleted file mode 100644 index 7ab8d0abc1a8..000000000000 --- a/.changeset/honest-kings-allow.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@rocket.chat/apps-engine': patch ---- - -Attempts to restart an app subprocess if the spawn command fails diff --git a/.changeset/kind-crabs-live.md b/.changeset/kind-crabs-live.md deleted file mode 100644 index 93b2218f828b..000000000000 --- a/.changeset/kind-crabs-live.md +++ /dev/null @@ -1,6 +0,0 @@ ---- -"@rocket.chat/meteor": patch -"@rocket.chat/i18n": patch ---- - -fixes "Change to language" button in login page not displaying the target language diff --git a/.changeset/lemon-singers-exercise.md b/.changeset/lemon-singers-exercise.md deleted file mode 100644 index 1e0e77d013c0..000000000000 --- a/.changeset/lemon-singers-exercise.md +++ /dev/null @@ -1,13 +0,0 @@ ---- -"@rocket.chat/i18n": patch ---- - -Changes the wording for voice call permissions, improving consistency and clarity. - -- `Manage Voip Extension` -> `Manage Voice Calls` - > Permission to manage voice calls and assign extensions to users -- `View VoIP extension details` -> `View Voice Call Extensions` - > Permission to view which user is calling and their extension info -- `View User VoIP extension` -> `Allow Voice Calls` - > Permission to allow users to use the voice call feature - diff --git a/.changeset/lemon-stingrays-invite.md b/.changeset/lemon-stingrays-invite.md deleted file mode 100644 index eb57df68c636..000000000000 --- a/.changeset/lemon-stingrays-invite.md +++ /dev/null @@ -1,9 +0,0 @@ ---- -'@rocket.chat/model-typings': minor -'@rocket.chat/core-typings': minor -'@rocket.chat/freeswitch': minor -'@rocket.chat/models': minor -'@rocket.chat/meteor': minor ---- - -Allows Rocket.Chat to store call events. diff --git a/.changeset/lovely-beers-argue.md b/.changeset/lovely-beers-argue.md deleted file mode 100644 index a01a97535e48..000000000000 --- a/.changeset/lovely-beers-argue.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@rocket.chat/meteor": patch ---- - -Fixes messages not being processed for all slack servers diff --git a/.changeset/lucky-mirrors-tickle.md b/.changeset/lucky-mirrors-tickle.md deleted file mode 100644 index ffc6e807d549..000000000000 --- a/.changeset/lucky-mirrors-tickle.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@rocket.chat/meteor': patch ---- - -Fixes an issue where premium settings were using the wrong `Tag` variant in Omnichannel Appearance configuration diff --git a/.changeset/lucky-wolves-turn.md b/.changeset/lucky-wolves-turn.md deleted file mode 100644 index 0dbb08af9e0f..000000000000 --- a/.changeset/lucky-wolves-turn.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@rocket.chat/meteor": patch ---- - -Fixes a UI issue that showed the incorrect migration number on the `Information` page. This was caused by a function calculating the stats before the server had migrated the database and updated the control. diff --git a/.changeset/metal-wolves-explode.md b/.changeset/metal-wolves-explode.md deleted file mode 100644 index e4acd9f51e32..000000000000 --- a/.changeset/metal-wolves-explode.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@rocket.chat/ui-voip": patch ---- - -Fixes an issue preventing VoIP permission updates from being properly reflected in the UI. diff --git a/.changeset/nervous-fireants-wash.md b/.changeset/nervous-fireants-wash.md deleted file mode 100644 index 441202512864..000000000000 --- a/.changeset/nervous-fireants-wash.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@rocket.chat/meteor": patch ---- - -Allows default avatars to be generated with more than one inital (limited to first 3) when setting `Use Full Name Initials to Generate Default Avatar` is true. diff --git a/.changeset/new-mails-add.md b/.changeset/new-mails-add.md deleted file mode 100644 index 87446ac8b4c1..000000000000 --- a/.changeset/new-mails-add.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@rocket.chat/livechat": patch ---- - -Fixes issue that caused different sessions when opening a livechat popover in cross domain diff --git a/.changeset/ninety-bulldogs-dream.md b/.changeset/ninety-bulldogs-dream.md deleted file mode 100644 index 1fe15fb79350..000000000000 --- a/.changeset/ninety-bulldogs-dream.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@rocket.chat/meteor": patch ---- - -Fixes an issue where removing the only message of a thread would keep the unread thread messages badge diff --git a/.changeset/perfect-ties-tell.md b/.changeset/perfect-ties-tell.md deleted file mode 100644 index e129fa0937c8..000000000000 --- a/.changeset/perfect-ties-tell.md +++ /dev/null @@ -1,21 +0,0 @@ ---- -"@rocket.chat/meteor": minor -"@rocket.chat/core-typings": minor -"@rocket.chat/model-typings": minor ---- - -Adds statistics related to the new **Contact Identification** feature: -- `totalContacts`: Total number of contacts; -- `totalUnknownContacts`: Total number of unknown contacts; -- `totalMergedContacts`: Total number of merged contacts; -- `totalConflicts`: Total number of merge conflicts; -- `totalResolvedConflicts`: Total number of resolved conflicts; -- `totalBlockedContacts`: Total number of blocked contacts; -- `totalPartiallyBlockedContacts`: Total number of partially blocked contacts; -- `totalFullyBlockedContacts`: Total number of fully blocked contacts; -- `totalVerifiedContacts`: Total number of verified contacts; -- `avgChannelsPerContact`: Average number of channels per contact; -- `totalContactsWithoutChannels`: Number of contacts without channels; -- `totalImportedContacts`: Total number of imported contacts; -- `totalUpsellViews`: Total number of "Advanced Contact Management" Upsell CTA views; -- `totalUpsellClicks`: Total number of "Advanced Contact Management" Upsell CTA clicks; diff --git a/.changeset/pretty-islands-wink.md b/.changeset/pretty-islands-wink.md deleted file mode 100644 index e9de264504b0..000000000000 --- a/.changeset/pretty-islands-wink.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@rocket.chat/meteor': minor ---- - -Disables OTR messages selection when exporting messages diff --git a/.changeset/proud-cups-share.md b/.changeset/proud-cups-share.md deleted file mode 100644 index eb51d15a9382..000000000000 --- a/.changeset/proud-cups-share.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@rocket.chat/meteor": patch ---- - -Fixes `im.counters` endpoint returning `null` on `unread` messages property for users that have never opened the queried DM diff --git a/.changeset/proud-planets-applaud.md b/.changeset/proud-planets-applaud.md deleted file mode 100644 index 7f692f780271..000000000000 --- a/.changeset/proud-planets-applaud.md +++ /dev/null @@ -1,22 +0,0 @@ ---- -'@rocket.chat/fuselage-ui-kit': patch -'@rocket.chat/instance-status': patch -'@rocket.chat/ui-theming': patch -'@rocket.chat/model-typings': patch -'@rocket.chat/ui-video-conf': patch -'@rocket.chat/uikit-playground': patch -'@rocket.chat/core-typings': patch -'@rocket.chat/rest-typings': patch -'@rocket.chat/apps-engine': patch -'@rocket.chat/ui-composer': patch -'@rocket.chat/ui-contexts': patch -'@rocket.chat/gazzodown': patch -'@rocket.chat/ui-avatar': patch -'@rocket.chat/ui-client': patch -'@rocket.chat/livechat': patch -'@rocket.chat/ui-voip': patch -'@rocket.chat/i18n': patch -'@rocket.chat/meteor': patch ---- - -Fixes wrong data being reported to total failed apps metrics and statistics diff --git a/.changeset/quiet-lions-unite.md b/.changeset/quiet-lions-unite.md deleted file mode 100644 index 723d773c0b02..000000000000 --- a/.changeset/quiet-lions-unite.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@rocket.chat/meteor': patch ---- - -Fixes sidepanel list not sorting by last message inside thread diff --git a/.changeset/quiet-radios-fry.md b/.changeset/quiet-radios-fry.md deleted file mode 100644 index b3b7209cb041..000000000000 --- a/.changeset/quiet-radios-fry.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@rocket.chat/apps-engine': patch ---- - -Fixes an issue while collecting the error message from a failed restart attempt of an app subprocess diff --git a/.changeset/real-crabs-grin.md b/.changeset/real-crabs-grin.md deleted file mode 100644 index fe0066e0183f..000000000000 --- a/.changeset/real-crabs-grin.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@rocket.chat/meteor': minor ---- - -Organizes App Settings interface by introducing section-based accordion groups to improve navigation and readability for administrators. diff --git a/.changeset/selfish-fishes-move.md b/.changeset/selfish-fishes-move.md deleted file mode 100644 index a227695cea89..000000000000 --- a/.changeset/selfish-fishes-move.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@rocket.chat/meteor": patch ---- - -fixes mail export form "To additional emails" field validation diff --git a/.changeset/seven-owls-tell.md b/.changeset/seven-owls-tell.md deleted file mode 100644 index 0c2cda791671..000000000000 --- a/.changeset/seven-owls-tell.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@rocket.chat/meteor": patch ---- - -Fixed an issue that added potencially infinite callbacks to the same event, degrading performance over time. diff --git a/.changeset/shaggy-bulldogs-beg.md b/.changeset/shaggy-bulldogs-beg.md deleted file mode 100644 index 211d11d7b67c..000000000000 --- a/.changeset/shaggy-bulldogs-beg.md +++ /dev/null @@ -1,7 +0,0 @@ ---- -'@rocket.chat/ui-composer': minor -'@rocket.chat/i18n': minor -'@rocket.chat/meteor': minor ---- - -Introduces a new option when exporting messages, allowing users to select and download a JSON file directly from client diff --git a/.changeset/six-snails-study.md b/.changeset/six-snails-study.md deleted file mode 100644 index 331bfacbbec1..000000000000 --- a/.changeset/six-snails-study.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@rocket.chat/meteor": patch ---- - -Fixes a behavior of the mentions parser that identified mentions inside markdown links text. Now, these components will be removed from the text before trying to parse mentions. diff --git a/.changeset/slow-readers-help.md b/.changeset/slow-readers-help.md deleted file mode 100644 index 2fe4881b56a0..000000000000 --- a/.changeset/slow-readers-help.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@rocket.chat/meteor": patch ---- - -Fixes an issue where the update banner wasn't showing the new version number diff --git a/.changeset/sour-guests-whisper.md b/.changeset/sour-guests-whisper.md deleted file mode 100644 index a012ce5fa310..000000000000 --- a/.changeset/sour-guests-whisper.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@rocket.chat/meteor': patch ---- - -Fixes an issue which caused action menu to be clipped in moderation page on smaller screens for better usability. diff --git a/.changeset/sour-roses-invite.md b/.changeset/sour-roses-invite.md deleted file mode 100644 index d560be689142..000000000000 --- a/.changeset/sour-roses-invite.md +++ /dev/null @@ -1,6 +0,0 @@ ---- -"@rocket.chat/meteor": minor ---- - -Improves the workspace and subscription admin pages by updating font scaling, centralizing elements, -enhancing responsiveness, and refactoring components to provide a better overall user experience. diff --git a/.changeset/strange-bulldogs-roll.md b/.changeset/strange-bulldogs-roll.md deleted file mode 100644 index 378299943599..000000000000 --- a/.changeset/strange-bulldogs-roll.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@rocket.chat/meteor': patch ---- - -Sorts the list of language options by name correctly \ No newline at end of file diff --git a/.changeset/strange-countries-carry.md b/.changeset/strange-countries-carry.md deleted file mode 100644 index 519448591957..000000000000 --- a/.changeset/strange-countries-carry.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@rocket.chat/meteor': patch ---- - -fixed an issue that caused the conference call ringer to fail to accept calls if the user logged out and in again diff --git a/.changeset/tidy-boxes-hide.md b/.changeset/tidy-boxes-hide.md deleted file mode 100644 index 33b8f0c812d0..000000000000 --- a/.changeset/tidy-boxes-hide.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@rocket.chat/meteor': patch ---- - -Fixes special characters not being escaped on sidepanel extended view diff --git a/.changeset/twelve-pumas-behave.md b/.changeset/twelve-pumas-behave.md new file mode 100644 index 000000000000..de651a34dbf2 --- /dev/null +++ b/.changeset/twelve-pumas-behave.md @@ -0,0 +1,5 @@ +--- +"@rocket.chat/meteor": patch +--- + +Fixes thumbnails not being deleted from storage on room deletion diff --git a/.changeset/violet-pets-attend.md b/.changeset/violet-pets-attend.md deleted file mode 100644 index f93079c94fa4..000000000000 --- a/.changeset/violet-pets-attend.md +++ /dev/null @@ -1,6 +0,0 @@ ---- -'@rocket.chat/ui-client': patch -'@rocket.chat/meteor': patch ---- - -Fixed the data structure of the features preview diff --git a/.changeset/wet-chicken-scream.md b/.changeset/wet-chicken-scream.md deleted file mode 100644 index 610be5e8cd44..000000000000 --- a/.changeset/wet-chicken-scream.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@rocket.chat/meteor": patch ---- - -Fixes contact update failing in case a custom field is removed from the workspace diff --git a/.changeset/wicked-socks-hide.md b/.changeset/wicked-socks-hide.md deleted file mode 100644 index 3f425c3228e2..000000000000 --- a/.changeset/wicked-socks-hide.md +++ /dev/null @@ -1,7 +0,0 @@ ---- -"@rocket.chat/meteor": minor -"@rocket.chat/core-typings": minor -"@rocket.chat/rest-typings": minor ---- - -Adds a new callout in the subscription page to inform users of subscription upgrade eligibility when applicable. diff --git a/.changeset/wise-queens-build.md b/.changeset/wise-queens-build.md deleted file mode 100644 index 51e54de4a6bd..000000000000 --- a/.changeset/wise-queens-build.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@rocket.chat/meteor': patch ---- - -Fixes an issue where the notification sound was playing randomly diff --git a/.changeset/young-dots-cheat.md b/.changeset/young-dots-cheat.md deleted file mode 100644 index e8d3b6c5bff6..000000000000 --- a/.changeset/young-dots-cheat.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@rocket.chat/apps-engine': patch ---- - -Prevents app:getStatus requests from timing out in some cases diff --git a/.github/workflows/ci-code-check.yml b/.github/workflows/ci-code-check.yml index ccdd37cf6ac4..3d4940e5cb0d 100644 --- a/.github/workflows/ci-code-check.yml +++ b/.github/workflows/ci-code-check.yml @@ -65,6 +65,27 @@ jobs: typecheck-cache-${{ runner.OS }} typecheck-cache + - name: Install Meteor + if: matrix.check == 'ts' + shell: bash + run: | + # Restore bin from cache + set +e + METEOR_SYMLINK_TARGET=$(readlink ~/.meteor/meteor) + METEOR_TOOL_DIRECTORY=$(dirname "$METEOR_SYMLINK_TARGET") + set -e + LAUNCHER=$HOME/.meteor/$METEOR_TOOL_DIRECTORY/scripts/admin/launch-meteor + if [ -e $LAUNCHER ] + then + echo "Cached Meteor bin found, restoring it" + sudo cp "$LAUNCHER" "/usr/local/bin/meteor" + else + echo "No cached Meteor bin found." + fi + + # only install meteor if bin isn't found + command -v meteor >/dev/null 2>&1 || curl https://install.meteor.com | sed s/--progress-bar/-sL/g | /bin/sh + - name: TS TypeCheck if: matrix.check == 'ts' run: yarn turbo run typecheck diff --git a/.github/workflows/ci-deploy-gh-pages.yml b/.github/workflows/ci-deploy-gh-pages.yml index abfe62d51389..6a343dd8476b 100644 --- a/.github/workflows/ci-deploy-gh-pages.yml +++ b/.github/workflows/ci-deploy-gh-pages.yml @@ -17,7 +17,7 @@ jobs: - name: Setup NodeJS uses: ./.github/actions/setup-node with: - node-version: 20.18.0 + node-version: 22.11.0 deno-version: 1.37.1 cache-modules: true install: true diff --git a/.github/workflows/ci-test-e2e.yml b/.github/workflows/ci-test-e2e.yml index 58dc52bb25d4..6a4aa84c8da4 100644 --- a/.github/workflows/ci-test-e2e.yml +++ b/.github/workflows/ci-test-e2e.yml @@ -114,7 +114,7 @@ jobs: password: ${{ secrets.CR_PAT }} - name: Launch MongoDB - uses: supercharge/mongodb-github-action@v1.10.0 + uses: supercharge/mongodb-github-action@1.12.0 with: mongodb-version: ${{ matrix.mongodb-version }} mongodb-replica-set: rs0 diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index c304cf836e17..b99c954aaa5a 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -199,7 +199,7 @@ jobs: uses: ./.github/actions/setup-node if: github.event.action != 'closed' with: - node-version: 20.18.0 + node-version: 22.11.0 deno-version: 1.37.1 cache-modules: true install: true diff --git a/.github/workflows/new-release.yml b/.github/workflows/new-release.yml index b3ead30e8966..73774c18cee2 100644 --- a/.github/workflows/new-release.yml +++ b/.github/workflows/new-release.yml @@ -34,7 +34,7 @@ jobs: - name: Setup NodeJS uses: ./.github/actions/setup-node with: - node-version: 20.18.0 + node-version: 22.11.0 deno-version: 1.37.1 cache-modules: true install: true diff --git a/.github/workflows/pr-update-description.yml b/.github/workflows/pr-update-description.yml index 7a0d8650a97f..0163404fb5e0 100644 --- a/.github/workflows/pr-update-description.yml +++ b/.github/workflows/pr-update-description.yml @@ -21,7 +21,7 @@ jobs: - name: Setup NodeJS uses: ./.github/actions/setup-node with: - node-version: 20.18.0 + node-version: 22.11.0 deno-version: 1.37.1 cache-modules: true install: true diff --git a/.github/workflows/publish-release.yml b/.github/workflows/publish-release.yml index 2f803576ef51..e45b88d5bca9 100644 --- a/.github/workflows/publish-release.yml +++ b/.github/workflows/publish-release.yml @@ -24,7 +24,7 @@ jobs: - name: Setup NodeJS uses: ./.github/actions/setup-node with: - node-version: 20.18.0 + node-version: 22.11.0 deno-version: 1.37.1 cache-modules: true install: true diff --git a/.github/workflows/release-candidate.yml b/.github/workflows/release-candidate.yml index 506f4cc1e5dd..640574d3eca3 100644 --- a/.github/workflows/release-candidate.yml +++ b/.github/workflows/release-candidate.yml @@ -15,7 +15,7 @@ jobs: - name: Setup NodeJS uses: ./.github/actions/setup-node with: - node-version: 20.18.0 + node-version: 22.11.0 deno-version: 1.37.1 cache-modules: true install: true diff --git a/.github/workflows/update-version-durability.yml b/.github/workflows/update-version-durability.yml index 45fd4859502b..1972e8181c71 100644 --- a/.github/workflows/update-version-durability.yml +++ b/.github/workflows/update-version-durability.yml @@ -19,7 +19,7 @@ jobs: - name: Use Node.js uses: actions/setup-node@v4.1.0 with: - node-version: '20.18.0' + node-version: '22.11.0' - name: Install dependencies run: | diff --git a/.gitpod.yml b/.gitpod.yml index e24ff7d2ebf1..b4caac9eb0d4 100644 --- a/.gitpod.yml +++ b/.gitpod.yml @@ -1,26 +1,19 @@ tasks: - init: | nvm install $(jq -r .engines.node package.json) && - curl https://install.meteor.com/ | sh && - export PATH="$PATH:$HOME/.meteor" && + curl https://install.meteor.com/?release=$( + curl -so- https://raw.githubusercontent.com/RocketChat/Rocket.Chat/develop/apps/meteor/.meteor/release | cut -d@ -f2 + ) | sh && + export PATH=$PATH:/home/gitpod/.meteor && yarn && export ROOT_URL=$(gp url 3000) - command: yarn build && yarn dev + command: yarn dsv ports: - port: 3000 visibility: public onOpen: open-preview -github: - prebuilds: - master: true - pullRequests: true - pullRequestsFromForks: true - addCheck: true - addComment: true - addBadge: true - vscode: extensions: - - esbenp.prettier-vscode \ No newline at end of file + - esbenp.prettier-vscode \ No newline at end of file diff --git a/.yarn/patches/@tanstack-react-query-npm-5.60.5-04c500b172.patch b/.yarn/patches/@tanstack-react-query-npm-5.60.5-04c500b172.patch new file mode 100644 index 000000000000..aac618f0c4ac --- /dev/null +++ b/.yarn/patches/@tanstack-react-query-npm-5.60.5-04c500b172.patch @@ -0,0 +1,830 @@ +diff --git a/build/legacy/useBaseQuery.cjs b/build/legacy/useBaseQuery.cjs +index b64ea5c5f9389e560ce6fd850dd3d52e8d2e6e73..82bfe43c9b2feeab44afe533aa0c70a3647ea627 100644 +--- a/build/legacy/useBaseQuery.cjs ++++ b/build/legacy/useBaseQuery.cjs +@@ -35,6 +35,7 @@ __export(useBaseQuery_exports, { + }); + module.exports = __toCommonJS(useBaseQuery_exports); + var React = __toESM(require("react"), 1); ++var import_shim = require("use-sync-external-store/shim/index.js"); + var import_query_core = require("@tanstack/query-core"); + var import_QueryClientProvider = require("./QueryClientProvider.cjs"); + var import_QueryErrorResetBoundary = require("./QueryErrorResetBoundary.cjs"); +@@ -71,7 +72,7 @@ function useBaseQuery(options, Observer, queryClient) { + ) + ); + const result = observer.getOptimisticResult(defaultedOptions); +- React.useSyncExternalStore( ++ (0, import_shim.useSyncExternalStore)( + React.useCallback( + (onStoreChange) => { + const unsubscribe = isRestoring ? import_utils.noop : observer.subscribe(import_query_core.notifyManager.batchCalls(onStoreChange)); +diff --git a/build/legacy/useBaseQuery.cjs.map b/build/legacy/useBaseQuery.cjs.map +index 0dad9cfafd6c15e84683ec40137a1cfa405a930b..46d962e7df4713b5d09a5aa4dba8d07abadd7a57 100644 +--- a/build/legacy/useBaseQuery.cjs.map ++++ b/build/legacy/useBaseQuery.cjs.map +@@ -1 +1 @@ +-{"version":3,"sources":["../../src/useBaseQuery.ts"],"sourcesContent":["'use client'\nimport * as React from 'react'\n\nimport { isServer, notifyManager } from '@tanstack/query-core'\nimport { useQueryClient } from './QueryClientProvider'\nimport { useQueryErrorResetBoundary } from './QueryErrorResetBoundary'\nimport {\n ensurePreventErrorBoundaryRetry,\n getHasError,\n useClearResetErrorBoundary,\n} from './errorBoundaryUtils'\nimport { useIsRestoring } from './isRestoring'\nimport {\n ensureSuspenseTimers,\n fetchOptimistic,\n shouldSuspend,\n willFetch,\n} from './suspense'\nimport { noop } from './utils'\nimport type {\n QueryClient,\n QueryKey,\n QueryObserver,\n QueryObserverResult,\n} from '@tanstack/query-core'\nimport type { UseBaseQueryOptions } from './types'\n\nexport function useBaseQuery<\n TQueryFnData,\n TError,\n TData,\n TQueryData,\n TQueryKey extends QueryKey,\n>(\n options: UseBaseQueryOptions<\n TQueryFnData,\n TError,\n TData,\n TQueryData,\n TQueryKey\n >,\n Observer: typeof QueryObserver,\n queryClient?: QueryClient,\n): QueryObserverResult {\n if (process.env.NODE_ENV !== 'production') {\n if (typeof options !== 'object' || Array.isArray(options)) {\n throw new Error(\n 'Bad argument type. Starting with v5, only the \"Object\" form is allowed when calling query related functions. Please use the error stack to find the culprit call. More info here: https://tanstack.com/query/latest/docs/react/guides/migrating-to-v5#supports-a-single-signature-one-object',\n )\n }\n }\n\n const client = useQueryClient(queryClient)\n const isRestoring = useIsRestoring()\n const errorResetBoundary = useQueryErrorResetBoundary()\n const defaultedOptions = client.defaultQueryOptions(options)\n\n ;(client.getDefaultOptions().queries as any)?._experimental_beforeQuery?.(\n defaultedOptions,\n )\n\n // Make sure results are optimistically set in fetching state before subscribing or updating options\n defaultedOptions._optimisticResults = isRestoring\n ? 'isRestoring'\n : 'optimistic'\n\n ensureSuspenseTimers(defaultedOptions)\n ensurePreventErrorBoundaryRetry(defaultedOptions, errorResetBoundary)\n\n useClearResetErrorBoundary(errorResetBoundary)\n\n // this needs to be invoked before creating the Observer because that can create a cache entry\n const isNewCacheEntry = !client\n .getQueryCache()\n .get(defaultedOptions.queryHash)\n\n const [observer] = React.useState(\n () =>\n new Observer(\n client,\n defaultedOptions,\n ),\n )\n\n const result = observer.getOptimisticResult(defaultedOptions)\n\n React.useSyncExternalStore(\n React.useCallback(\n (onStoreChange) => {\n const unsubscribe = isRestoring\n ? noop\n : observer.subscribe(notifyManager.batchCalls(onStoreChange))\n\n // Update result to make sure we did not miss any query updates\n // between creating the observer and subscribing to it.\n observer.updateResult()\n\n return unsubscribe\n },\n [observer, isRestoring],\n ),\n () => observer.getCurrentResult(),\n () => observer.getCurrentResult(),\n )\n\n React.useEffect(() => {\n // Do not notify on updates because of changes in the options because\n // these changes should already be reflected in the optimistic result.\n observer.setOptions(defaultedOptions, { listeners: false })\n }, [defaultedOptions, observer])\n\n // Handle suspense\n if (shouldSuspend(defaultedOptions, result)) {\n throw fetchOptimistic(defaultedOptions, observer, errorResetBoundary)\n }\n\n // Handle error boundary\n if (\n getHasError({\n result,\n errorResetBoundary,\n throwOnError: defaultedOptions.throwOnError,\n query: client\n .getQueryCache()\n .get<\n TQueryFnData,\n TError,\n TQueryData,\n TQueryKey\n >(defaultedOptions.queryHash),\n })\n ) {\n throw result.error\n }\n\n ;(client.getDefaultOptions().queries as any)?._experimental_afterQuery?.(\n defaultedOptions,\n result,\n )\n\n if (\n defaultedOptions.experimental_prefetchInRender &&\n !isServer &&\n willFetch(result, isRestoring)\n ) {\n const promise = isNewCacheEntry\n ? // Fetch immediately on render in order to ensure `.promise` is resolved even if the component is unmounted\n fetchOptimistic(defaultedOptions, observer, errorResetBoundary)\n : // subscribe to the \"cache promise\" so that we can finalize the currentThenable once data comes in\n client.getQueryCache().get(defaultedOptions.queryHash)?.promise\n\n promise?.catch(noop).finally(() => {\n // `.updateResult()` will trigger `.#currentThenable` to finalize\n observer.updateResult()\n })\n }\n\n // Handle result property usage tracking\n return !defaultedOptions.notifyOnChangeProps\n ? observer.trackResult(result)\n : result\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AACA,YAAuB;AAEvB,wBAAwC;AACxC,iCAA+B;AAC/B,qCAA2C;AAC3C,gCAIO;AACP,yBAA+B;AAC/B,sBAKO;AACP,mBAAqB;AASd,SAAS,aAOd,SAOA,UACA,aACoC;AA3CtC;AA4CE,MAAI,QAAQ,IAAI,aAAa,cAAc;AACzC,QAAI,OAAO,YAAY,YAAY,MAAM,QAAQ,OAAO,GAAG;AACzD,YAAM,IAAI;AAAA,QACR;AAAA,MACF;AAAA,IACF;AAAA,EACF;AAEA,QAAM,aAAS,2CAAe,WAAW;AACzC,QAAM,kBAAc,mCAAe;AACnC,QAAM,yBAAqB,2DAA2B;AACtD,QAAM,mBAAmB,OAAO,oBAAoB,OAAO;AAE1D,GAAC,kBAAO,kBAAkB,EAAE,YAA3B,mBAA4C,8BAA5C;AAAA;AAAA,IACA;AAAA;AAIF,mBAAiB,qBAAqB,cAClC,gBACA;AAEJ,4CAAqB,gBAAgB;AACrC,iEAAgC,kBAAkB,kBAAkB;AAEpE,4DAA2B,kBAAkB;AAG7C,QAAM,kBAAkB,CAAC,OACtB,cAAc,EACd,IAAI,iBAAiB,SAAS;AAEjC,QAAM,CAAC,QAAQ,IAAU;AAAA,IACvB,MACE,IAAI;AAAA,MACF;AAAA,MACA;AAAA,IACF;AAAA,EACJ;AAEA,QAAM,SAAS,SAAS,oBAAoB,gBAAgB;AAE5D,EAAM;AAAA,IACE;AAAA,MACJ,CAAC,kBAAkB;AACjB,cAAM,cAAc,cAChB,oBACA,SAAS,UAAU,gCAAc,WAAW,aAAa,CAAC;AAI9D,iBAAS,aAAa;AAEtB,eAAO;AAAA,MACT;AAAA,MACA,CAAC,UAAU,WAAW;AAAA,IACxB;AAAA,IACA,MAAM,SAAS,iBAAiB;AAAA,IAChC,MAAM,SAAS,iBAAiB;AAAA,EAClC;AAEA,EAAM,gBAAU,MAAM;AAGpB,aAAS,WAAW,kBAAkB,EAAE,WAAW,MAAM,CAAC;AAAA,EAC5D,GAAG,CAAC,kBAAkB,QAAQ,CAAC;AAG/B,UAAI,+BAAc,kBAAkB,MAAM,GAAG;AAC3C,cAAM,iCAAgB,kBAAkB,UAAU,kBAAkB;AAAA,EACtE;AAGA,UACE,uCAAY;AAAA,IACV;AAAA,IACA;AAAA,IACA,cAAc,iBAAiB;AAAA,IAC/B,OAAO,OACJ,cAAc,EACd,IAKC,iBAAiB,SAAS;AAAA,EAChC,CAAC,GACD;AACA,UAAM,OAAO;AAAA,EACf;AAEA;AAAC,GAAC,kBAAO,kBAAkB,EAAE,YAA3B,mBAA4C,6BAA5C;AAAA;AAAA,IACA;AAAA,IACA;AAAA;AAGF,MACE,iBAAiB,iCACjB,CAAC,kCACD,2BAAU,QAAQ,WAAW,GAC7B;AACA,UAAM,UAAU;AAAA;AAAA,UAEZ,iCAAgB,kBAAkB,UAAU,kBAAkB;AAAA;AAAA;AAAA,OAE9D,YAAO,cAAc,EAAE,IAAI,iBAAiB,SAAS,MAArD,mBAAwD;AAAA;AAE5D,uCAAS,MAAM,mBAAM,QAAQ,MAAM;AAEjC,eAAS,aAAa;AAAA,IACxB;AAAA,EACF;AAGA,SAAO,CAAC,iBAAiB,sBACrB,SAAS,YAAY,MAAM,IAC3B;AACN;","names":[]} +\ No newline at end of file ++{"version":3,"sources":["../../src/useBaseQuery.ts"],"sourcesContent":["'use client'\nimport * as React from 'react'\nimport { useSyncExternalStore } from 'use-sync-external-store/shim/index.js'\n\nimport { isServer, notifyManager } from '@tanstack/query-core'\nimport { useQueryClient } from './QueryClientProvider'\nimport { useQueryErrorResetBoundary } from './QueryErrorResetBoundary'\nimport {\n ensurePreventErrorBoundaryRetry,\n getHasError,\n useClearResetErrorBoundary,\n} from './errorBoundaryUtils'\nimport { useIsRestoring } from './isRestoring'\nimport {\n ensureSuspenseTimers,\n fetchOptimistic,\n shouldSuspend,\n willFetch,\n} from './suspense'\nimport { noop } from './utils'\nimport type {\n QueryClient,\n QueryKey,\n QueryObserver,\n QueryObserverResult,\n} from '@tanstack/query-core'\nimport type { UseBaseQueryOptions } from './types'\n\nexport function useBaseQuery<\n TQueryFnData,\n TError,\n TData,\n TQueryData,\n TQueryKey extends QueryKey,\n>(\n options: UseBaseQueryOptions<\n TQueryFnData,\n TError,\n TData,\n TQueryData,\n TQueryKey\n >,\n Observer: typeof QueryObserver,\n queryClient?: QueryClient,\n): QueryObserverResult {\n if (process.env.NODE_ENV !== 'production') {\n if (typeof options !== 'object' || Array.isArray(options)) {\n throw new Error(\n 'Bad argument type. Starting with v5, only the \"Object\" form is allowed when calling query related functions. Please use the error stack to find the culprit call. More info here: https://tanstack.com/query/latest/docs/react/guides/migrating-to-v5#supports-a-single-signature-one-object',\n )\n }\n }\n\n const client = useQueryClient(queryClient)\n const isRestoring = useIsRestoring()\n const errorResetBoundary = useQueryErrorResetBoundary()\n const defaultedOptions = client.defaultQueryOptions(options)\n\n ;(client.getDefaultOptions().queries as any)?._experimental_beforeQuery?.(\n defaultedOptions,\n )\n\n // Make sure results are optimistically set in fetching state before subscribing or updating options\n defaultedOptions._optimisticResults = isRestoring\n ? 'isRestoring'\n : 'optimistic'\n\n ensureSuspenseTimers(defaultedOptions)\n ensurePreventErrorBoundaryRetry(defaultedOptions, errorResetBoundary)\n\n useClearResetErrorBoundary(errorResetBoundary)\n\n // this needs to be invoked before creating the Observer because that can create a cache entry\n const isNewCacheEntry = !client\n .getQueryCache()\n .get(defaultedOptions.queryHash)\n\n const [observer] = React.useState(\n () =>\n new Observer(\n client,\n defaultedOptions,\n ),\n )\n\n const result = observer.getOptimisticResult(defaultedOptions)\n\n useSyncExternalStore(\n React.useCallback(\n (onStoreChange) => {\n const unsubscribe = isRestoring\n ? noop\n : observer.subscribe(notifyManager.batchCalls(onStoreChange))\n\n // Update result to make sure we did not miss any query updates\n // between creating the observer and subscribing to it.\n observer.updateResult()\n\n return unsubscribe\n },\n [observer, isRestoring],\n ),\n () => observer.getCurrentResult(),\n () => observer.getCurrentResult(),\n )\n\n React.useEffect(() => {\n // Do not notify on updates because of changes in the options because\n // these changes should already be reflected in the optimistic result.\n observer.setOptions(defaultedOptions, { listeners: false })\n }, [defaultedOptions, observer])\n\n // Handle suspense\n if (shouldSuspend(defaultedOptions, result)) {\n throw fetchOptimistic(defaultedOptions, observer, errorResetBoundary)\n }\n\n // Handle error boundary\n if (\n getHasError({\n result,\n errorResetBoundary,\n throwOnError: defaultedOptions.throwOnError,\n query: client\n .getQueryCache()\n .get<\n TQueryFnData,\n TError,\n TQueryData,\n TQueryKey\n >(defaultedOptions.queryHash),\n })\n ) {\n throw result.error\n }\n\n ;(client.getDefaultOptions().queries as any)?._experimental_afterQuery?.(\n defaultedOptions,\n result,\n )\n\n if (\n defaultedOptions.experimental_prefetchInRender &&\n !isServer &&\n willFetch(result, isRestoring)\n ) {\n const promise = isNewCacheEntry\n ? // Fetch immediately on render in order to ensure `.promise` is resolved even if the component is unmounted\n fetchOptimistic(defaultedOptions, observer, errorResetBoundary)\n : // subscribe to the \"cache promise\" so that we can finalize the currentThenable once data comes in\n client.getQueryCache().get(defaultedOptions.queryHash)?.promise\n\n promise?.catch(noop).finally(() => {\n // `.updateResult()` will trigger `.#currentThenable` to finalize\n observer.updateResult()\n })\n }\n\n // Handle result property usage tracking\n return !defaultedOptions.notifyOnChangeProps\n ? observer.trackResult(result)\n : result\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AACA,YAAuB;AACvB,kBAAqC;AAErC,wBAAwC;AACxC,iCAA+B;AAC/B,qCAA2C;AAC3C,gCAIO;AACP,yBAA+B;AAC/B,sBAKO;AACP,mBAAqB;AASd,SAAS,aAOd,SAOA,UACA,aACoC;AA5CtC;AA6CE,MAAI,QAAQ,IAAI,aAAa,cAAc;AACzC,QAAI,OAAO,YAAY,YAAY,MAAM,QAAQ,OAAO,GAAG;AACzD,YAAM,IAAI;AAAA,QACR;AAAA,MACF;AAAA,IACF;AAAA,EACF;AAEA,QAAM,aAAS,2CAAe,WAAW;AACzC,QAAM,kBAAc,mCAAe;AACnC,QAAM,yBAAqB,2DAA2B;AACtD,QAAM,mBAAmB,OAAO,oBAAoB,OAAO;AAE1D,GAAC,kBAAO,kBAAkB,EAAE,YAA3B,mBAA4C,8BAA5C;AAAA;AAAA,IACA;AAAA;AAIF,mBAAiB,qBAAqB,cAClC,gBACA;AAEJ,4CAAqB,gBAAgB;AACrC,iEAAgC,kBAAkB,kBAAkB;AAEpE,4DAA2B,kBAAkB;AAG7C,QAAM,kBAAkB,CAAC,OACtB,cAAc,EACd,IAAI,iBAAiB,SAAS;AAEjC,QAAM,CAAC,QAAQ,IAAU;AAAA,IACvB,MACE,IAAI;AAAA,MACF;AAAA,MACA;AAAA,IACF;AAAA,EACJ;AAEA,QAAM,SAAS,SAAS,oBAAoB,gBAAgB;AAE5D;AAAA,IACQ;AAAA,MACJ,CAAC,kBAAkB;AACjB,cAAM,cAAc,cAChB,oBACA,SAAS,UAAU,gCAAc,WAAW,aAAa,CAAC;AAI9D,iBAAS,aAAa;AAEtB,eAAO;AAAA,MACT;AAAA,MACA,CAAC,UAAU,WAAW;AAAA,IACxB;AAAA,IACA,MAAM,SAAS,iBAAiB;AAAA,IAChC,MAAM,SAAS,iBAAiB;AAAA,EAClC;AAEA,EAAM,gBAAU,MAAM;AAGpB,aAAS,WAAW,kBAAkB,EAAE,WAAW,MAAM,CAAC;AAAA,EAC5D,GAAG,CAAC,kBAAkB,QAAQ,CAAC;AAG/B,UAAI,+BAAc,kBAAkB,MAAM,GAAG;AAC3C,cAAM,iCAAgB,kBAAkB,UAAU,kBAAkB;AAAA,EACtE;AAGA,UACE,uCAAY;AAAA,IACV;AAAA,IACA;AAAA,IACA,cAAc,iBAAiB;AAAA,IAC/B,OAAO,OACJ,cAAc,EACd,IAKC,iBAAiB,SAAS;AAAA,EAChC,CAAC,GACD;AACA,UAAM,OAAO;AAAA,EACf;AAEA;AAAC,GAAC,kBAAO,kBAAkB,EAAE,YAA3B,mBAA4C,6BAA5C;AAAA;AAAA,IACA;AAAA,IACA;AAAA;AAGF,MACE,iBAAiB,iCACjB,CAAC,kCACD,2BAAU,QAAQ,WAAW,GAC7B;AACA,UAAM,UAAU;AAAA;AAAA,UAEZ,iCAAgB,kBAAkB,UAAU,kBAAkB;AAAA;AAAA;AAAA,OAE9D,YAAO,cAAc,EAAE,IAAI,iBAAiB,SAAS,MAArD,mBAAwD;AAAA;AAE5D,uCAAS,MAAM,mBAAM,QAAQ,MAAM;AAEjC,eAAS,aAAa;AAAA,IACxB;AAAA,EACF;AAGA,SAAO,CAAC,iBAAiB,sBACrB,SAAS,YAAY,MAAM,IAC3B;AACN;","names":[]} +\ No newline at end of file +diff --git a/build/legacy/useBaseQuery.js b/build/legacy/useBaseQuery.js +index daadb39a71bcb61c20aab33031b2c8be5a02df42..52f4e2ba490165672001eac667e008099da286c4 100644 +--- a/build/legacy/useBaseQuery.js ++++ b/build/legacy/useBaseQuery.js +@@ -2,6 +2,7 @@ + + // src/useBaseQuery.ts + import * as React from "react"; ++import { useSyncExternalStore } from "use-sync-external-store/shim/index.js"; + import { isServer, notifyManager } from "@tanstack/query-core"; + import { useQueryClient } from "./QueryClientProvider.js"; + import { useQueryErrorResetBoundary } from "./QueryErrorResetBoundary.js"; +@@ -47,7 +48,7 @@ function useBaseQuery(options, Observer, queryClient) { + ) + ); + const result = observer.getOptimisticResult(defaultedOptions); +- React.useSyncExternalStore( ++ useSyncExternalStore( + React.useCallback( + (onStoreChange) => { + const unsubscribe = isRestoring ? noop : observer.subscribe(notifyManager.batchCalls(onStoreChange)); +diff --git a/build/legacy/useBaseQuery.js.map b/build/legacy/useBaseQuery.js.map +index c4d3cbf5623b5f9869df7d4cc7da99e61cd97cba..9db12605d968f471b72dc91559216e3b13e6acdd 100644 +--- a/build/legacy/useBaseQuery.js.map ++++ b/build/legacy/useBaseQuery.js.map +@@ -1 +1 @@ +-{"version":3,"sources":["../../src/useBaseQuery.ts"],"sourcesContent":["'use client'\nimport * as React from 'react'\n\nimport { isServer, notifyManager } from '@tanstack/query-core'\nimport { useQueryClient } from './QueryClientProvider'\nimport { useQueryErrorResetBoundary } from './QueryErrorResetBoundary'\nimport {\n ensurePreventErrorBoundaryRetry,\n getHasError,\n useClearResetErrorBoundary,\n} from './errorBoundaryUtils'\nimport { useIsRestoring } from './isRestoring'\nimport {\n ensureSuspenseTimers,\n fetchOptimistic,\n shouldSuspend,\n willFetch,\n} from './suspense'\nimport { noop } from './utils'\nimport type {\n QueryClient,\n QueryKey,\n QueryObserver,\n QueryObserverResult,\n} from '@tanstack/query-core'\nimport type { UseBaseQueryOptions } from './types'\n\nexport function useBaseQuery<\n TQueryFnData,\n TError,\n TData,\n TQueryData,\n TQueryKey extends QueryKey,\n>(\n options: UseBaseQueryOptions<\n TQueryFnData,\n TError,\n TData,\n TQueryData,\n TQueryKey\n >,\n Observer: typeof QueryObserver,\n queryClient?: QueryClient,\n): QueryObserverResult {\n if (process.env.NODE_ENV !== 'production') {\n if (typeof options !== 'object' || Array.isArray(options)) {\n throw new Error(\n 'Bad argument type. Starting with v5, only the \"Object\" form is allowed when calling query related functions. Please use the error stack to find the culprit call. More info here: https://tanstack.com/query/latest/docs/react/guides/migrating-to-v5#supports-a-single-signature-one-object',\n )\n }\n }\n\n const client = useQueryClient(queryClient)\n const isRestoring = useIsRestoring()\n const errorResetBoundary = useQueryErrorResetBoundary()\n const defaultedOptions = client.defaultQueryOptions(options)\n\n ;(client.getDefaultOptions().queries as any)?._experimental_beforeQuery?.(\n defaultedOptions,\n )\n\n // Make sure results are optimistically set in fetching state before subscribing or updating options\n defaultedOptions._optimisticResults = isRestoring\n ? 'isRestoring'\n : 'optimistic'\n\n ensureSuspenseTimers(defaultedOptions)\n ensurePreventErrorBoundaryRetry(defaultedOptions, errorResetBoundary)\n\n useClearResetErrorBoundary(errorResetBoundary)\n\n // this needs to be invoked before creating the Observer because that can create a cache entry\n const isNewCacheEntry = !client\n .getQueryCache()\n .get(defaultedOptions.queryHash)\n\n const [observer] = React.useState(\n () =>\n new Observer(\n client,\n defaultedOptions,\n ),\n )\n\n const result = observer.getOptimisticResult(defaultedOptions)\n\n React.useSyncExternalStore(\n React.useCallback(\n (onStoreChange) => {\n const unsubscribe = isRestoring\n ? noop\n : observer.subscribe(notifyManager.batchCalls(onStoreChange))\n\n // Update result to make sure we did not miss any query updates\n // between creating the observer and subscribing to it.\n observer.updateResult()\n\n return unsubscribe\n },\n [observer, isRestoring],\n ),\n () => observer.getCurrentResult(),\n () => observer.getCurrentResult(),\n )\n\n React.useEffect(() => {\n // Do not notify on updates because of changes in the options because\n // these changes should already be reflected in the optimistic result.\n observer.setOptions(defaultedOptions, { listeners: false })\n }, [defaultedOptions, observer])\n\n // Handle suspense\n if (shouldSuspend(defaultedOptions, result)) {\n throw fetchOptimistic(defaultedOptions, observer, errorResetBoundary)\n }\n\n // Handle error boundary\n if (\n getHasError({\n result,\n errorResetBoundary,\n throwOnError: defaultedOptions.throwOnError,\n query: client\n .getQueryCache()\n .get<\n TQueryFnData,\n TError,\n TQueryData,\n TQueryKey\n >(defaultedOptions.queryHash),\n })\n ) {\n throw result.error\n }\n\n ;(client.getDefaultOptions().queries as any)?._experimental_afterQuery?.(\n defaultedOptions,\n result,\n )\n\n if (\n defaultedOptions.experimental_prefetchInRender &&\n !isServer &&\n willFetch(result, isRestoring)\n ) {\n const promise = isNewCacheEntry\n ? // Fetch immediately on render in order to ensure `.promise` is resolved even if the component is unmounted\n fetchOptimistic(defaultedOptions, observer, errorResetBoundary)\n : // subscribe to the \"cache promise\" so that we can finalize the currentThenable once data comes in\n client.getQueryCache().get(defaultedOptions.queryHash)?.promise\n\n promise?.catch(noop).finally(() => {\n // `.updateResult()` will trigger `.#currentThenable` to finalize\n observer.updateResult()\n })\n }\n\n // Handle result property usage tracking\n return !defaultedOptions.notifyOnChangeProps\n ? observer.trackResult(result)\n : result\n}\n"],"mappings":";;;AACA,YAAY,WAAW;AAEvB,SAAS,UAAU,qBAAqB;AACxC,SAAS,sBAAsB;AAC/B,SAAS,kCAAkC;AAC3C;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,OACK;AACP,SAAS,sBAAsB;AAC/B;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OACK;AACP,SAAS,YAAY;AASd,SAAS,aAOd,SAOA,UACA,aACoC;AA3CtC;AA4CE,MAAI,QAAQ,IAAI,aAAa,cAAc;AACzC,QAAI,OAAO,YAAY,YAAY,MAAM,QAAQ,OAAO,GAAG;AACzD,YAAM,IAAI;AAAA,QACR;AAAA,MACF;AAAA,IACF;AAAA,EACF;AAEA,QAAM,SAAS,eAAe,WAAW;AACzC,QAAM,cAAc,eAAe;AACnC,QAAM,qBAAqB,2BAA2B;AACtD,QAAM,mBAAmB,OAAO,oBAAoB,OAAO;AAE1D,GAAC,kBAAO,kBAAkB,EAAE,YAA3B,mBAA4C,8BAA5C;AAAA;AAAA,IACA;AAAA;AAIF,mBAAiB,qBAAqB,cAClC,gBACA;AAEJ,uBAAqB,gBAAgB;AACrC,kCAAgC,kBAAkB,kBAAkB;AAEpE,6BAA2B,kBAAkB;AAG7C,QAAM,kBAAkB,CAAC,OACtB,cAAc,EACd,IAAI,iBAAiB,SAAS;AAEjC,QAAM,CAAC,QAAQ,IAAU;AAAA,IACvB,MACE,IAAI;AAAA,MACF;AAAA,MACA;AAAA,IACF;AAAA,EACJ;AAEA,QAAM,SAAS,SAAS,oBAAoB,gBAAgB;AAE5D,EAAM;AAAA,IACE;AAAA,MACJ,CAAC,kBAAkB;AACjB,cAAM,cAAc,cAChB,OACA,SAAS,UAAU,cAAc,WAAW,aAAa,CAAC;AAI9D,iBAAS,aAAa;AAEtB,eAAO;AAAA,MACT;AAAA,MACA,CAAC,UAAU,WAAW;AAAA,IACxB;AAAA,IACA,MAAM,SAAS,iBAAiB;AAAA,IAChC,MAAM,SAAS,iBAAiB;AAAA,EAClC;AAEA,EAAM,gBAAU,MAAM;AAGpB,aAAS,WAAW,kBAAkB,EAAE,WAAW,MAAM,CAAC;AAAA,EAC5D,GAAG,CAAC,kBAAkB,QAAQ,CAAC;AAG/B,MAAI,cAAc,kBAAkB,MAAM,GAAG;AAC3C,UAAM,gBAAgB,kBAAkB,UAAU,kBAAkB;AAAA,EACtE;AAGA,MACE,YAAY;AAAA,IACV;AAAA,IACA;AAAA,IACA,cAAc,iBAAiB;AAAA,IAC/B,OAAO,OACJ,cAAc,EACd,IAKC,iBAAiB,SAAS;AAAA,EAChC,CAAC,GACD;AACA,UAAM,OAAO;AAAA,EACf;AAEA;AAAC,GAAC,kBAAO,kBAAkB,EAAE,YAA3B,mBAA4C,6BAA5C;AAAA;AAAA,IACA;AAAA,IACA;AAAA;AAGF,MACE,iBAAiB,iCACjB,CAAC,YACD,UAAU,QAAQ,WAAW,GAC7B;AACA,UAAM,UAAU;AAAA;AAAA,MAEZ,gBAAgB,kBAAkB,UAAU,kBAAkB;AAAA;AAAA;AAAA,OAE9D,YAAO,cAAc,EAAE,IAAI,iBAAiB,SAAS,MAArD,mBAAwD;AAAA;AAE5D,uCAAS,MAAM,MAAM,QAAQ,MAAM;AAEjC,eAAS,aAAa;AAAA,IACxB;AAAA,EACF;AAGA,SAAO,CAAC,iBAAiB,sBACrB,SAAS,YAAY,MAAM,IAC3B;AACN;","names":[]} +\ No newline at end of file ++{"version":3,"sources":["../../src/useBaseQuery.ts"],"sourcesContent":["'use client'\nimport * as React from 'react'\nimport { useSyncExternalStore } from 'use-sync-external-store/shim/index.js'\n\nimport { isServer, notifyManager } from '@tanstack/query-core'\nimport { useQueryClient } from './QueryClientProvider'\nimport { useQueryErrorResetBoundary } from './QueryErrorResetBoundary'\nimport {\n ensurePreventErrorBoundaryRetry,\n getHasError,\n useClearResetErrorBoundary,\n} from './errorBoundaryUtils'\nimport { useIsRestoring } from './isRestoring'\nimport {\n ensureSuspenseTimers,\n fetchOptimistic,\n shouldSuspend,\n willFetch,\n} from './suspense'\nimport { noop } from './utils'\nimport type {\n QueryClient,\n QueryKey,\n QueryObserver,\n QueryObserverResult,\n} from '@tanstack/query-core'\nimport type { UseBaseQueryOptions } from './types'\n\nexport function useBaseQuery<\n TQueryFnData,\n TError,\n TData,\n TQueryData,\n TQueryKey extends QueryKey,\n>(\n options: UseBaseQueryOptions<\n TQueryFnData,\n TError,\n TData,\n TQueryData,\n TQueryKey\n >,\n Observer: typeof QueryObserver,\n queryClient?: QueryClient,\n): QueryObserverResult {\n if (process.env.NODE_ENV !== 'production') {\n if (typeof options !== 'object' || Array.isArray(options)) {\n throw new Error(\n 'Bad argument type. Starting with v5, only the \"Object\" form is allowed when calling query related functions. Please use the error stack to find the culprit call. More info here: https://tanstack.com/query/latest/docs/react/guides/migrating-to-v5#supports-a-single-signature-one-object',\n )\n }\n }\n\n const client = useQueryClient(queryClient)\n const isRestoring = useIsRestoring()\n const errorResetBoundary = useQueryErrorResetBoundary()\n const defaultedOptions = client.defaultQueryOptions(options)\n\n ;(client.getDefaultOptions().queries as any)?._experimental_beforeQuery?.(\n defaultedOptions,\n )\n\n // Make sure results are optimistically set in fetching state before subscribing or updating options\n defaultedOptions._optimisticResults = isRestoring\n ? 'isRestoring'\n : 'optimistic'\n\n ensureSuspenseTimers(defaultedOptions)\n ensurePreventErrorBoundaryRetry(defaultedOptions, errorResetBoundary)\n\n useClearResetErrorBoundary(errorResetBoundary)\n\n // this needs to be invoked before creating the Observer because that can create a cache entry\n const isNewCacheEntry = !client\n .getQueryCache()\n .get(defaultedOptions.queryHash)\n\n const [observer] = React.useState(\n () =>\n new Observer(\n client,\n defaultedOptions,\n ),\n )\n\n const result = observer.getOptimisticResult(defaultedOptions)\n\n useSyncExternalStore(\n React.useCallback(\n (onStoreChange) => {\n const unsubscribe = isRestoring\n ? noop\n : observer.subscribe(notifyManager.batchCalls(onStoreChange))\n\n // Update result to make sure we did not miss any query updates\n // between creating the observer and subscribing to it.\n observer.updateResult()\n\n return unsubscribe\n },\n [observer, isRestoring],\n ),\n () => observer.getCurrentResult(),\n () => observer.getCurrentResult(),\n )\n\n React.useEffect(() => {\n // Do not notify on updates because of changes in the options because\n // these changes should already be reflected in the optimistic result.\n observer.setOptions(defaultedOptions, { listeners: false })\n }, [defaultedOptions, observer])\n\n // Handle suspense\n if (shouldSuspend(defaultedOptions, result)) {\n throw fetchOptimistic(defaultedOptions, observer, errorResetBoundary)\n }\n\n // Handle error boundary\n if (\n getHasError({\n result,\n errorResetBoundary,\n throwOnError: defaultedOptions.throwOnError,\n query: client\n .getQueryCache()\n .get<\n TQueryFnData,\n TError,\n TQueryData,\n TQueryKey\n >(defaultedOptions.queryHash),\n })\n ) {\n throw result.error\n }\n\n ;(client.getDefaultOptions().queries as any)?._experimental_afterQuery?.(\n defaultedOptions,\n result,\n )\n\n if (\n defaultedOptions.experimental_prefetchInRender &&\n !isServer &&\n willFetch(result, isRestoring)\n ) {\n const promise = isNewCacheEntry\n ? // Fetch immediately on render in order to ensure `.promise` is resolved even if the component is unmounted\n fetchOptimistic(defaultedOptions, observer, errorResetBoundary)\n : // subscribe to the \"cache promise\" so that we can finalize the currentThenable once data comes in\n client.getQueryCache().get(defaultedOptions.queryHash)?.promise\n\n promise?.catch(noop).finally(() => {\n // `.updateResult()` will trigger `.#currentThenable` to finalize\n observer.updateResult()\n })\n }\n\n // Handle result property usage tracking\n return !defaultedOptions.notifyOnChangeProps\n ? observer.trackResult(result)\n : result\n}\n"],"mappings":";;;AACA,YAAY,WAAW;AACvB,SAAS,4BAA4B;AAErC,SAAS,UAAU,qBAAqB;AACxC,SAAS,sBAAsB;AAC/B,SAAS,kCAAkC;AAC3C;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,OACK;AACP,SAAS,sBAAsB;AAC/B;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OACK;AACP,SAAS,YAAY;AASd,SAAS,aAOd,SAOA,UACA,aACoC;AA5CtC;AA6CE,MAAI,QAAQ,IAAI,aAAa,cAAc;AACzC,QAAI,OAAO,YAAY,YAAY,MAAM,QAAQ,OAAO,GAAG;AACzD,YAAM,IAAI;AAAA,QACR;AAAA,MACF;AAAA,IACF;AAAA,EACF;AAEA,QAAM,SAAS,eAAe,WAAW;AACzC,QAAM,cAAc,eAAe;AACnC,QAAM,qBAAqB,2BAA2B;AACtD,QAAM,mBAAmB,OAAO,oBAAoB,OAAO;AAE1D,GAAC,kBAAO,kBAAkB,EAAE,YAA3B,mBAA4C,8BAA5C;AAAA;AAAA,IACA;AAAA;AAIF,mBAAiB,qBAAqB,cAClC,gBACA;AAEJ,uBAAqB,gBAAgB;AACrC,kCAAgC,kBAAkB,kBAAkB;AAEpE,6BAA2B,kBAAkB;AAG7C,QAAM,kBAAkB,CAAC,OACtB,cAAc,EACd,IAAI,iBAAiB,SAAS;AAEjC,QAAM,CAAC,QAAQ,IAAU;AAAA,IACvB,MACE,IAAI;AAAA,MACF;AAAA,MACA;AAAA,IACF;AAAA,EACJ;AAEA,QAAM,SAAS,SAAS,oBAAoB,gBAAgB;AAE5D;AAAA,IACQ;AAAA,MACJ,CAAC,kBAAkB;AACjB,cAAM,cAAc,cAChB,OACA,SAAS,UAAU,cAAc,WAAW,aAAa,CAAC;AAI9D,iBAAS,aAAa;AAEtB,eAAO;AAAA,MACT;AAAA,MACA,CAAC,UAAU,WAAW;AAAA,IACxB;AAAA,IACA,MAAM,SAAS,iBAAiB;AAAA,IAChC,MAAM,SAAS,iBAAiB;AAAA,EAClC;AAEA,EAAM,gBAAU,MAAM;AAGpB,aAAS,WAAW,kBAAkB,EAAE,WAAW,MAAM,CAAC;AAAA,EAC5D,GAAG,CAAC,kBAAkB,QAAQ,CAAC;AAG/B,MAAI,cAAc,kBAAkB,MAAM,GAAG;AAC3C,UAAM,gBAAgB,kBAAkB,UAAU,kBAAkB;AAAA,EACtE;AAGA,MACE,YAAY;AAAA,IACV;AAAA,IACA;AAAA,IACA,cAAc,iBAAiB;AAAA,IAC/B,OAAO,OACJ,cAAc,EACd,IAKC,iBAAiB,SAAS;AAAA,EAChC,CAAC,GACD;AACA,UAAM,OAAO;AAAA,EACf;AAEA;AAAC,GAAC,kBAAO,kBAAkB,EAAE,YAA3B,mBAA4C,6BAA5C;AAAA;AAAA,IACA;AAAA,IACA;AAAA;AAGF,MACE,iBAAiB,iCACjB,CAAC,YACD,UAAU,QAAQ,WAAW,GAC7B;AACA,UAAM,UAAU;AAAA;AAAA,MAEZ,gBAAgB,kBAAkB,UAAU,kBAAkB;AAAA;AAAA;AAAA,OAE9D,YAAO,cAAc,EAAE,IAAI,iBAAiB,SAAS,MAArD,mBAAwD;AAAA;AAE5D,uCAAS,MAAM,MAAM,QAAQ,MAAM;AAEjC,eAAS,aAAa;AAAA,IACxB;AAAA,EACF;AAGA,SAAO,CAAC,iBAAiB,sBACrB,SAAS,YAAY,MAAM,IAC3B;AACN;","names":[]} +\ No newline at end of file +diff --git a/build/legacy/useIsFetching.cjs b/build/legacy/useIsFetching.cjs +index 28660e7d19489acc86f6a2f0c9b47e453ac66fae..2bed8ddef2f97adfb60c35aa83630259898e5e20 100644 +--- a/build/legacy/useIsFetching.cjs ++++ b/build/legacy/useIsFetching.cjs +@@ -35,12 +35,13 @@ __export(useIsFetching_exports, { + }); + module.exports = __toCommonJS(useIsFetching_exports); + var React = __toESM(require("react"), 1); ++var import_shim = require("use-sync-external-store/shim/index.js"); + var import_query_core = require("@tanstack/query-core"); + var import_QueryClientProvider = require("./QueryClientProvider.cjs"); + function useIsFetching(filters, queryClient) { + const client = (0, import_QueryClientProvider.useQueryClient)(queryClient); + const queryCache = client.getQueryCache(); +- return React.useSyncExternalStore( ++ return (0, import_shim.useSyncExternalStore)( + React.useCallback( + (onStoreChange) => queryCache.subscribe(import_query_core.notifyManager.batchCalls(onStoreChange)), + [queryCache] +diff --git a/build/legacy/useIsFetching.cjs.map b/build/legacy/useIsFetching.cjs.map +index 5a58e86806e2919b9dcfbaf0cc3c32a4e23a5661..d3d112b618dc78caf24b36510852fdd647381c0a 100644 +--- a/build/legacy/useIsFetching.cjs.map ++++ b/build/legacy/useIsFetching.cjs.map +@@ -1 +1 @@ +-{"version":3,"sources":["../../src/useIsFetching.ts"],"sourcesContent":["'use client'\nimport * as React from 'react'\nimport { notifyManager } from '@tanstack/query-core'\n\nimport { useQueryClient } from './QueryClientProvider'\nimport type { QueryClient, QueryFilters } from '@tanstack/query-core'\n\nexport function useIsFetching(\n filters?: QueryFilters,\n queryClient?: QueryClient,\n): number {\n const client = useQueryClient(queryClient)\n const queryCache = client.getQueryCache()\n\n return React.useSyncExternalStore(\n React.useCallback(\n (onStoreChange) =>\n queryCache.subscribe(notifyManager.batchCalls(onStoreChange)),\n [queryCache],\n ),\n () => client.isFetching(filters),\n () => client.isFetching(filters),\n )\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AACA,YAAuB;AACvB,wBAA8B;AAE9B,iCAA+B;AAGxB,SAAS,cACd,SACA,aACQ;AACR,QAAM,aAAS,2CAAe,WAAW;AACzC,QAAM,aAAa,OAAO,cAAc;AAExC,SAAa;AAAA,IACL;AAAA,MACJ,CAAC,kBACC,WAAW,UAAU,gCAAc,WAAW,aAAa,CAAC;AAAA,MAC9D,CAAC,UAAU;AAAA,IACb;AAAA,IACA,MAAM,OAAO,WAAW,OAAO;AAAA,IAC/B,MAAM,OAAO,WAAW,OAAO;AAAA,EACjC;AACF;","names":[]} +\ No newline at end of file ++{"version":3,"sources":["../../src/useIsFetching.ts"],"sourcesContent":["'use client'\nimport * as React from 'react'\nimport { useSyncExternalStore } from 'use-sync-external-store/shim/index.js'\n\nimport { notifyManager } from '@tanstack/query-core'\n\nimport { useQueryClient } from './QueryClientProvider'\nimport type { QueryClient, QueryFilters } from '@tanstack/query-core'\n\nexport function useIsFetching(\n filters?: QueryFilters,\n queryClient?: QueryClient,\n): number {\n const client = useQueryClient(queryClient)\n const queryCache = client.getQueryCache()\n\n return useSyncExternalStore(\n React.useCallback(\n (onStoreChange) =>\n queryCache.subscribe(notifyManager.batchCalls(onStoreChange)),\n [queryCache],\n ),\n () => client.isFetching(filters),\n () => client.isFetching(filters),\n )\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AACA,YAAuB;AACvB,kBAAqC;AAErC,wBAA8B;AAE9B,iCAA+B;AAGxB,SAAS,cACd,SACA,aACQ;AACR,QAAM,aAAS,2CAAe,WAAW;AACzC,QAAM,aAAa,OAAO,cAAc;AAExC,aAAO;AAAA,IACC;AAAA,MACJ,CAAC,kBACC,WAAW,UAAU,gCAAc,WAAW,aAAa,CAAC;AAAA,MAC9D,CAAC,UAAU;AAAA,IACb;AAAA,IACA,MAAM,OAAO,WAAW,OAAO;AAAA,IAC/B,MAAM,OAAO,WAAW,OAAO;AAAA,EACjC;AACF;","names":[]} +\ No newline at end of file +diff --git a/build/legacy/useIsFetching.js b/build/legacy/useIsFetching.js +index acfc67a302d371b13b632cfdfcba1740ac6cfa22..90af8d148cbedb97df0b11b64fe84b4db973acd4 100644 +--- a/build/legacy/useIsFetching.js ++++ b/build/legacy/useIsFetching.js +@@ -2,12 +2,13 @@ + + // src/useIsFetching.ts + import * as React from "react"; ++import { useSyncExternalStore } from "use-sync-external-store/shim/index.js"; + import { notifyManager } from "@tanstack/query-core"; + import { useQueryClient } from "./QueryClientProvider.js"; + function useIsFetching(filters, queryClient) { + const client = useQueryClient(queryClient); + const queryCache = client.getQueryCache(); +- return React.useSyncExternalStore( ++ return useSyncExternalStore( + React.useCallback( + (onStoreChange) => queryCache.subscribe(notifyManager.batchCalls(onStoreChange)), + [queryCache] +diff --git a/build/legacy/useIsFetching.js.map b/build/legacy/useIsFetching.js.map +index 9921ab6e20952d564197ef61fccc3ab1f4943bd0..4b13c50e8e70381758c583c3b8cfbd0180d13a04 100644 +--- a/build/legacy/useIsFetching.js.map ++++ b/build/legacy/useIsFetching.js.map +@@ -1 +1 @@ +-{"version":3,"sources":["../../src/useIsFetching.ts"],"sourcesContent":["'use client'\nimport * as React from 'react'\nimport { notifyManager } from '@tanstack/query-core'\n\nimport { useQueryClient } from './QueryClientProvider'\nimport type { QueryClient, QueryFilters } from '@tanstack/query-core'\n\nexport function useIsFetching(\n filters?: QueryFilters,\n queryClient?: QueryClient,\n): number {\n const client = useQueryClient(queryClient)\n const queryCache = client.getQueryCache()\n\n return React.useSyncExternalStore(\n React.useCallback(\n (onStoreChange) =>\n queryCache.subscribe(notifyManager.batchCalls(onStoreChange)),\n [queryCache],\n ),\n () => client.isFetching(filters),\n () => client.isFetching(filters),\n )\n}\n"],"mappings":";;;AACA,YAAY,WAAW;AACvB,SAAS,qBAAqB;AAE9B,SAAS,sBAAsB;AAGxB,SAAS,cACd,SACA,aACQ;AACR,QAAM,SAAS,eAAe,WAAW;AACzC,QAAM,aAAa,OAAO,cAAc;AAExC,SAAa;AAAA,IACL;AAAA,MACJ,CAAC,kBACC,WAAW,UAAU,cAAc,WAAW,aAAa,CAAC;AAAA,MAC9D,CAAC,UAAU;AAAA,IACb;AAAA,IACA,MAAM,OAAO,WAAW,OAAO;AAAA,IAC/B,MAAM,OAAO,WAAW,OAAO;AAAA,EACjC;AACF;","names":[]} +\ No newline at end of file ++{"version":3,"sources":["../../src/useIsFetching.ts"],"sourcesContent":["'use client'\nimport * as React from 'react'\nimport { useSyncExternalStore } from 'use-sync-external-store/shim/index.js'\n\nimport { notifyManager } from '@tanstack/query-core'\n\nimport { useQueryClient } from './QueryClientProvider'\nimport type { QueryClient, QueryFilters } from '@tanstack/query-core'\n\nexport function useIsFetching(\n filters?: QueryFilters,\n queryClient?: QueryClient,\n): number {\n const client = useQueryClient(queryClient)\n const queryCache = client.getQueryCache()\n\n return useSyncExternalStore(\n React.useCallback(\n (onStoreChange) =>\n queryCache.subscribe(notifyManager.batchCalls(onStoreChange)),\n [queryCache],\n ),\n () => client.isFetching(filters),\n () => client.isFetching(filters),\n )\n}\n"],"mappings":";;;AACA,YAAY,WAAW;AACvB,SAAS,4BAA4B;AAErC,SAAS,qBAAqB;AAE9B,SAAS,sBAAsB;AAGxB,SAAS,cACd,SACA,aACQ;AACR,QAAM,SAAS,eAAe,WAAW;AACzC,QAAM,aAAa,OAAO,cAAc;AAExC,SAAO;AAAA,IACC;AAAA,MACJ,CAAC,kBACC,WAAW,UAAU,cAAc,WAAW,aAAa,CAAC;AAAA,MAC9D,CAAC,UAAU;AAAA,IACb;AAAA,IACA,MAAM,OAAO,WAAW,OAAO;AAAA,IAC/B,MAAM,OAAO,WAAW,OAAO;AAAA,EACjC;AACF;","names":[]} +\ No newline at end of file +diff --git a/build/legacy/useMutation.cjs b/build/legacy/useMutation.cjs +index 175de467172e7c876d51141d22f151de482d2a43..826a83d5f08d22035d1f8bd31a0236299055dec3 100644 +--- a/build/legacy/useMutation.cjs ++++ b/build/legacy/useMutation.cjs +@@ -35,6 +35,7 @@ __export(useMutation_exports, { + }); + module.exports = __toCommonJS(useMutation_exports); + var React = __toESM(require("react"), 1); ++var import_shim = require("use-sync-external-store/shim/index.js"); + var import_query_core = require("@tanstack/query-core"); + var import_QueryClientProvider = require("./QueryClientProvider.cjs"); + var import_utils = require("./utils.cjs"); +@@ -49,7 +50,7 @@ function useMutation(options, queryClient) { + React.useEffect(() => { + observer.setOptions(options); + }, [observer, options]); +- const result = React.useSyncExternalStore( ++ const result = (0, import_shim.useSyncExternalStore)( + React.useCallback( + (onStoreChange) => observer.subscribe(import_query_core.notifyManager.batchCalls(onStoreChange)), + [observer] +diff --git a/build/legacy/useMutation.cjs.map b/build/legacy/useMutation.cjs.map +index 2beaf7a697d67be63bb22ae4739b0db0eeede8f7..ffd27eb4f52319afc1afa4122c9982f6484591bd 100644 +--- a/build/legacy/useMutation.cjs.map ++++ b/build/legacy/useMutation.cjs.map +@@ -1 +1 @@ +-{"version":3,"sources":["../../src/useMutation.ts"],"sourcesContent":["'use client'\nimport * as React from 'react'\nimport { MutationObserver, notifyManager } from '@tanstack/query-core'\nimport { useQueryClient } from './QueryClientProvider'\nimport { noop, shouldThrowError } from './utils'\nimport type {\n UseMutateFunction,\n UseMutationOptions,\n UseMutationResult,\n} from './types'\nimport type { DefaultError, QueryClient } from '@tanstack/query-core'\n\n// HOOK\n\nexport function useMutation<\n TData = unknown,\n TError = DefaultError,\n TVariables = void,\n TContext = unknown,\n>(\n options: UseMutationOptions,\n queryClient?: QueryClient,\n): UseMutationResult {\n const client = useQueryClient(queryClient)\n\n const [observer] = React.useState(\n () =>\n new MutationObserver(\n client,\n options,\n ),\n )\n\n React.useEffect(() => {\n observer.setOptions(options)\n }, [observer, options])\n\n const result = React.useSyncExternalStore(\n React.useCallback(\n (onStoreChange) =>\n observer.subscribe(notifyManager.batchCalls(onStoreChange)),\n [observer],\n ),\n () => observer.getCurrentResult(),\n () => observer.getCurrentResult(),\n )\n\n const mutate = React.useCallback<\n UseMutateFunction\n >(\n (variables, mutateOptions) => {\n observer.mutate(variables, mutateOptions).catch(noop)\n },\n [observer],\n )\n\n if (\n result.error &&\n shouldThrowError(observer.options.throwOnError, [result.error])\n ) {\n throw result.error\n }\n\n return { ...result, mutate, mutateAsync: result.mutate }\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AACA,YAAuB;AACvB,wBAAgD;AAChD,iCAA+B;AAC/B,mBAAuC;AAUhC,SAAS,YAMd,SACA,aACwD;AACxD,QAAM,aAAS,2CAAe,WAAW;AAEzC,QAAM,CAAC,QAAQ,IAAU;AAAA,IACvB,MACE,IAAI;AAAA,MACF;AAAA,MACA;AAAA,IACF;AAAA,EACJ;AAEA,EAAM,gBAAU,MAAM;AACpB,aAAS,WAAW,OAAO;AAAA,EAC7B,GAAG,CAAC,UAAU,OAAO,CAAC;AAEtB,QAAM,SAAe;AAAA,IACb;AAAA,MACJ,CAAC,kBACC,SAAS,UAAU,gCAAc,WAAW,aAAa,CAAC;AAAA,MAC5D,CAAC,QAAQ;AAAA,IACX;AAAA,IACA,MAAM,SAAS,iBAAiB;AAAA,IAChC,MAAM,SAAS,iBAAiB;AAAA,EAClC;AAEA,QAAM,SAAe;AAAA,IAGnB,CAAC,WAAW,kBAAkB;AAC5B,eAAS,OAAO,WAAW,aAAa,EAAE,MAAM,iBAAI;AAAA,IACtD;AAAA,IACA,CAAC,QAAQ;AAAA,EACX;AAEA,MACE,OAAO,aACP,+BAAiB,SAAS,QAAQ,cAAc,CAAC,OAAO,KAAK,CAAC,GAC9D;AACA,UAAM,OAAO;AAAA,EACf;AAEA,SAAO,EAAE,GAAG,QAAQ,QAAQ,aAAa,OAAO,OAAO;AACzD;","names":[]} +\ No newline at end of file ++{"version":3,"sources":["../../src/useMutation.ts"],"sourcesContent":["'use client'\nimport * as React from 'react'\nimport { useSyncExternalStore } from 'use-sync-external-store/shim/index.js'\n\nimport { MutationObserver, notifyManager } from '@tanstack/query-core'\nimport { useQueryClient } from './QueryClientProvider'\nimport { noop, shouldThrowError } from './utils'\nimport type {\n UseMutateFunction,\n UseMutationOptions,\n UseMutationResult,\n} from './types'\nimport type { DefaultError, QueryClient } from '@tanstack/query-core'\n\n// HOOK\n\nexport function useMutation<\n TData = unknown,\n TError = DefaultError,\n TVariables = void,\n TContext = unknown,\n>(\n options: UseMutationOptions,\n queryClient?: QueryClient,\n): UseMutationResult {\n const client = useQueryClient(queryClient)\n\n const [observer] = React.useState(\n () =>\n new MutationObserver(\n client,\n options,\n ),\n )\n\n React.useEffect(() => {\n observer.setOptions(options)\n }, [observer, options])\n\n const result = useSyncExternalStore(\n React.useCallback(\n (onStoreChange) =>\n observer.subscribe(notifyManager.batchCalls(onStoreChange)),\n [observer],\n ),\n () => observer.getCurrentResult(),\n () => observer.getCurrentResult(),\n )\n\n const mutate = React.useCallback<\n UseMutateFunction\n >(\n (variables, mutateOptions) => {\n observer.mutate(variables, mutateOptions).catch(noop)\n },\n [observer],\n )\n\n if (\n result.error &&\n shouldThrowError(observer.options.throwOnError, [result.error])\n ) {\n throw result.error\n }\n\n return { ...result, mutate, mutateAsync: result.mutate }\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AACA,YAAuB;AACvB,kBAAqC;AAErC,wBAAgD;AAChD,iCAA+B;AAC/B,mBAAuC;AAUhC,SAAS,YAMd,SACA,aACwD;AACxD,QAAM,aAAS,2CAAe,WAAW;AAEzC,QAAM,CAAC,QAAQ,IAAU;AAAA,IACvB,MACE,IAAI;AAAA,MACF;AAAA,MACA;AAAA,IACF;AAAA,EACJ;AAEA,EAAM,gBAAU,MAAM;AACpB,aAAS,WAAW,OAAO;AAAA,EAC7B,GAAG,CAAC,UAAU,OAAO,CAAC;AAEtB,QAAM,aAAS;AAAA,IACP;AAAA,MACJ,CAAC,kBACC,SAAS,UAAU,gCAAc,WAAW,aAAa,CAAC;AAAA,MAC5D,CAAC,QAAQ;AAAA,IACX;AAAA,IACA,MAAM,SAAS,iBAAiB;AAAA,IAChC,MAAM,SAAS,iBAAiB;AAAA,EAClC;AAEA,QAAM,SAAe;AAAA,IAGnB,CAAC,WAAW,kBAAkB;AAC5B,eAAS,OAAO,WAAW,aAAa,EAAE,MAAM,iBAAI;AAAA,IACtD;AAAA,IACA,CAAC,QAAQ;AAAA,EACX;AAEA,MACE,OAAO,aACP,+BAAiB,SAAS,QAAQ,cAAc,CAAC,OAAO,KAAK,CAAC,GAC9D;AACA,UAAM,OAAO;AAAA,EACf;AAEA,SAAO,EAAE,GAAG,QAAQ,QAAQ,aAAa,OAAO,OAAO;AACzD;","names":[]} +\ No newline at end of file +diff --git a/build/legacy/useMutation.js b/build/legacy/useMutation.js +index 515a3b92ecf8c348ccc7f16de4f778301327e9c9..a135e33b89a5cf9ef8d1725a9aada6283052bed9 100644 +--- a/build/legacy/useMutation.js ++++ b/build/legacy/useMutation.js +@@ -2,6 +2,7 @@ + + // src/useMutation.ts + import * as React from "react"; ++import { useSyncExternalStore } from "use-sync-external-store/shim/index.js"; + import { MutationObserver, notifyManager } from "@tanstack/query-core"; + import { useQueryClient } from "./QueryClientProvider.js"; + import { noop, shouldThrowError } from "./utils.js"; +@@ -16,7 +17,7 @@ function useMutation(options, queryClient) { + React.useEffect(() => { + observer.setOptions(options); + }, [observer, options]); +- const result = React.useSyncExternalStore( ++ const result = useSyncExternalStore( + React.useCallback( + (onStoreChange) => observer.subscribe(notifyManager.batchCalls(onStoreChange)), + [observer] +diff --git a/build/legacy/useMutation.js.map b/build/legacy/useMutation.js.map +index 0627ad75983fcc9d6cd9d66a20f7a935dd076ad4..03013010c6b9d825c2888d9ac03edc774e8b7965 100644 +--- a/build/legacy/useMutation.js.map ++++ b/build/legacy/useMutation.js.map +@@ -1 +1 @@ +-{"version":3,"sources":["../../src/useMutation.ts"],"sourcesContent":["'use client'\nimport * as React from 'react'\nimport { MutationObserver, notifyManager } from '@tanstack/query-core'\nimport { useQueryClient } from './QueryClientProvider'\nimport { noop, shouldThrowError } from './utils'\nimport type {\n UseMutateFunction,\n UseMutationOptions,\n UseMutationResult,\n} from './types'\nimport type { DefaultError, QueryClient } from '@tanstack/query-core'\n\n// HOOK\n\nexport function useMutation<\n TData = unknown,\n TError = DefaultError,\n TVariables = void,\n TContext = unknown,\n>(\n options: UseMutationOptions,\n queryClient?: QueryClient,\n): UseMutationResult {\n const client = useQueryClient(queryClient)\n\n const [observer] = React.useState(\n () =>\n new MutationObserver(\n client,\n options,\n ),\n )\n\n React.useEffect(() => {\n observer.setOptions(options)\n }, [observer, options])\n\n const result = React.useSyncExternalStore(\n React.useCallback(\n (onStoreChange) =>\n observer.subscribe(notifyManager.batchCalls(onStoreChange)),\n [observer],\n ),\n () => observer.getCurrentResult(),\n () => observer.getCurrentResult(),\n )\n\n const mutate = React.useCallback<\n UseMutateFunction\n >(\n (variables, mutateOptions) => {\n observer.mutate(variables, mutateOptions).catch(noop)\n },\n [observer],\n )\n\n if (\n result.error &&\n shouldThrowError(observer.options.throwOnError, [result.error])\n ) {\n throw result.error\n }\n\n return { ...result, mutate, mutateAsync: result.mutate }\n}\n"],"mappings":";;;AACA,YAAY,WAAW;AACvB,SAAS,kBAAkB,qBAAqB;AAChD,SAAS,sBAAsB;AAC/B,SAAS,MAAM,wBAAwB;AAUhC,SAAS,YAMd,SACA,aACwD;AACxD,QAAM,SAAS,eAAe,WAAW;AAEzC,QAAM,CAAC,QAAQ,IAAU;AAAA,IACvB,MACE,IAAI;AAAA,MACF;AAAA,MACA;AAAA,IACF;AAAA,EACJ;AAEA,EAAM,gBAAU,MAAM;AACpB,aAAS,WAAW,OAAO;AAAA,EAC7B,GAAG,CAAC,UAAU,OAAO,CAAC;AAEtB,QAAM,SAAe;AAAA,IACb;AAAA,MACJ,CAAC,kBACC,SAAS,UAAU,cAAc,WAAW,aAAa,CAAC;AAAA,MAC5D,CAAC,QAAQ;AAAA,IACX;AAAA,IACA,MAAM,SAAS,iBAAiB;AAAA,IAChC,MAAM,SAAS,iBAAiB;AAAA,EAClC;AAEA,QAAM,SAAe;AAAA,IAGnB,CAAC,WAAW,kBAAkB;AAC5B,eAAS,OAAO,WAAW,aAAa,EAAE,MAAM,IAAI;AAAA,IACtD;AAAA,IACA,CAAC,QAAQ;AAAA,EACX;AAEA,MACE,OAAO,SACP,iBAAiB,SAAS,QAAQ,cAAc,CAAC,OAAO,KAAK,CAAC,GAC9D;AACA,UAAM,OAAO;AAAA,EACf;AAEA,SAAO,EAAE,GAAG,QAAQ,QAAQ,aAAa,OAAO,OAAO;AACzD;","names":[]} +\ No newline at end of file ++{"version":3,"sources":["../../src/useMutation.ts"],"sourcesContent":["'use client'\nimport * as React from 'react'\nimport { useSyncExternalStore } from 'use-sync-external-store/shim/index.js'\n\nimport { MutationObserver, notifyManager } from '@tanstack/query-core'\nimport { useQueryClient } from './QueryClientProvider'\nimport { noop, shouldThrowError } from './utils'\nimport type {\n UseMutateFunction,\n UseMutationOptions,\n UseMutationResult,\n} from './types'\nimport type { DefaultError, QueryClient } from '@tanstack/query-core'\n\n// HOOK\n\nexport function useMutation<\n TData = unknown,\n TError = DefaultError,\n TVariables = void,\n TContext = unknown,\n>(\n options: UseMutationOptions,\n queryClient?: QueryClient,\n): UseMutationResult {\n const client = useQueryClient(queryClient)\n\n const [observer] = React.useState(\n () =>\n new MutationObserver(\n client,\n options,\n ),\n )\n\n React.useEffect(() => {\n observer.setOptions(options)\n }, [observer, options])\n\n const result = useSyncExternalStore(\n React.useCallback(\n (onStoreChange) =>\n observer.subscribe(notifyManager.batchCalls(onStoreChange)),\n [observer],\n ),\n () => observer.getCurrentResult(),\n () => observer.getCurrentResult(),\n )\n\n const mutate = React.useCallback<\n UseMutateFunction\n >(\n (variables, mutateOptions) => {\n observer.mutate(variables, mutateOptions).catch(noop)\n },\n [observer],\n )\n\n if (\n result.error &&\n shouldThrowError(observer.options.throwOnError, [result.error])\n ) {\n throw result.error\n }\n\n return { ...result, mutate, mutateAsync: result.mutate }\n}\n"],"mappings":";;;AACA,YAAY,WAAW;AACvB,SAAS,4BAA4B;AAErC,SAAS,kBAAkB,qBAAqB;AAChD,SAAS,sBAAsB;AAC/B,SAAS,MAAM,wBAAwB;AAUhC,SAAS,YAMd,SACA,aACwD;AACxD,QAAM,SAAS,eAAe,WAAW;AAEzC,QAAM,CAAC,QAAQ,IAAU;AAAA,IACvB,MACE,IAAI;AAAA,MACF;AAAA,MACA;AAAA,IACF;AAAA,EACJ;AAEA,EAAM,gBAAU,MAAM;AACpB,aAAS,WAAW,OAAO;AAAA,EAC7B,GAAG,CAAC,UAAU,OAAO,CAAC;AAEtB,QAAM,SAAS;AAAA,IACP;AAAA,MACJ,CAAC,kBACC,SAAS,UAAU,cAAc,WAAW,aAAa,CAAC;AAAA,MAC5D,CAAC,QAAQ;AAAA,IACX;AAAA,IACA,MAAM,SAAS,iBAAiB;AAAA,IAChC,MAAM,SAAS,iBAAiB;AAAA,EAClC;AAEA,QAAM,SAAe;AAAA,IAGnB,CAAC,WAAW,kBAAkB;AAC5B,eAAS,OAAO,WAAW,aAAa,EAAE,MAAM,IAAI;AAAA,IACtD;AAAA,IACA,CAAC,QAAQ;AAAA,EACX;AAEA,MACE,OAAO,SACP,iBAAiB,SAAS,QAAQ,cAAc,CAAC,OAAO,KAAK,CAAC,GAC9D;AACA,UAAM,OAAO;AAAA,EACf;AAEA,SAAO,EAAE,GAAG,QAAQ,QAAQ,aAAa,OAAO,OAAO;AACzD;","names":[]} +\ No newline at end of file +diff --git a/build/legacy/useMutationState.cjs b/build/legacy/useMutationState.cjs +index 0248bea1b0a0922589748a9338d85be66fc3468c..0bb6d8ac2eacb572b35c29429ef5d94edf33b7ad 100644 +--- a/build/legacy/useMutationState.cjs ++++ b/build/legacy/useMutationState.cjs +@@ -36,6 +36,7 @@ __export(useMutationState_exports, { + }); + module.exports = __toCommonJS(useMutationState_exports); + var React = __toESM(require("react"), 1); ++var import_shim = require("use-sync-external-store/shim/index.js"); + var import_query_core = require("@tanstack/query-core"); + var import_QueryClientProvider = require("./QueryClientProvider.cjs"); + function useIsMutating(filters, queryClient) { +@@ -60,7 +61,7 @@ function useMutationState(options = {}, queryClient) { + React.useEffect(() => { + optionsRef.current = options; + }); +- return React.useSyncExternalStore( ++ return (0, import_shim.useSyncExternalStore)( + React.useCallback( + (onStoreChange) => mutationCache.subscribe(() => { + const nextResult = (0, import_query_core.replaceEqualDeep)( +diff --git a/build/legacy/useMutationState.cjs.map b/build/legacy/useMutationState.cjs.map +index 68b0a392336cba75982a1146353c1e14698fca14..6383002ae8e9b97a4390db3bcead0e1955925ac6 100644 +--- a/build/legacy/useMutationState.cjs.map ++++ b/build/legacy/useMutationState.cjs.map +@@ -1 +1 @@ +-{"version":3,"sources":["../../src/useMutationState.ts"],"sourcesContent":["/* eslint-disable react-compiler/react-compiler */\n\n'use client'\nimport * as React from 'react'\n\nimport { notifyManager, replaceEqualDeep } from '@tanstack/query-core'\nimport { useQueryClient } from './QueryClientProvider'\nimport type {\n Mutation,\n MutationCache,\n MutationFilters,\n MutationState,\n QueryClient,\n} from '@tanstack/query-core'\n\nexport function useIsMutating(\n filters?: MutationFilters,\n queryClient?: QueryClient,\n): number {\n const client = useQueryClient(queryClient)\n return useMutationState(\n { filters: { ...filters, status: 'pending' } },\n client,\n ).length\n}\n\ntype MutationStateOptions = {\n filters?: MutationFilters\n select?: (mutation: Mutation) => TResult\n}\n\nfunction getResult(\n mutationCache: MutationCache,\n options: MutationStateOptions,\n): Array {\n return mutationCache\n .findAll(options.filters)\n .map(\n (mutation): TResult =>\n (options.select ? options.select(mutation) : mutation.state) as TResult,\n )\n}\n\nexport function useMutationState(\n options: MutationStateOptions = {},\n queryClient?: QueryClient,\n): Array {\n const mutationCache = useQueryClient(queryClient).getMutationCache()\n const optionsRef = React.useRef(options)\n const result = React.useRef>(null)\n if (!result.current) {\n result.current = getResult(mutationCache, options)\n }\n\n React.useEffect(() => {\n optionsRef.current = options\n })\n\n return React.useSyncExternalStore(\n React.useCallback(\n (onStoreChange) =>\n mutationCache.subscribe(() => {\n const nextResult = replaceEqualDeep(\n result.current,\n getResult(mutationCache, optionsRef.current),\n )\n if (result.current !== nextResult) {\n result.current = nextResult\n notifyManager.schedule(onStoreChange)\n }\n }),\n [mutationCache],\n ),\n () => result.current,\n () => result.current,\n )!\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAGA,YAAuB;AAEvB,wBAAgD;AAChD,iCAA+B;AASxB,SAAS,cACd,SACA,aACQ;AACR,QAAM,aAAS,2CAAe,WAAW;AACzC,SAAO;AAAA,IACL,EAAE,SAAS,EAAE,GAAG,SAAS,QAAQ,UAAU,EAAE;AAAA,IAC7C;AAAA,EACF,EAAE;AACJ;AAOA,SAAS,UACP,eACA,SACgB;AAChB,SAAO,cACJ,QAAQ,QAAQ,OAAO,EACvB;AAAA,IACC,CAAC,aACE,QAAQ,SAAS,QAAQ,OAAO,QAAQ,IAAI,SAAS;AAAA,EAC1D;AACJ;AAEO,SAAS,iBACd,UAAyC,CAAC,GAC1C,aACgB;AAChB,QAAM,oBAAgB,2CAAe,WAAW,EAAE,iBAAiB;AACnE,QAAM,aAAmB,aAAO,OAAO;AACvC,QAAM,SAAe,aAAuB,IAAI;AAChD,MAAI,CAAC,OAAO,SAAS;AACnB,WAAO,UAAU,UAAU,eAAe,OAAO;AAAA,EACnD;AAEA,EAAM,gBAAU,MAAM;AACpB,eAAW,UAAU;AAAA,EACvB,CAAC;AAED,SAAa;AAAA,IACL;AAAA,MACJ,CAAC,kBACC,cAAc,UAAU,MAAM;AAC5B,cAAM,iBAAa;AAAA,UACjB,OAAO;AAAA,UACP,UAAU,eAAe,WAAW,OAAO;AAAA,QAC7C;AACA,YAAI,OAAO,YAAY,YAAY;AACjC,iBAAO,UAAU;AACjB,0CAAc,SAAS,aAAa;AAAA,QACtC;AAAA,MACF,CAAC;AAAA,MACH,CAAC,aAAa;AAAA,IAChB;AAAA,IACA,MAAM,OAAO;AAAA,IACb,MAAM,OAAO;AAAA,EACf;AACF;","names":[]} +\ No newline at end of file ++{"version":3,"sources":["../../src/useMutationState.ts"],"sourcesContent":["/* eslint-disable react-compiler/react-compiler */\n\n'use client'\nimport * as React from 'react'\nimport { useSyncExternalStore } from 'use-sync-external-store/shim/index.js'\n\nimport { notifyManager, replaceEqualDeep } from '@tanstack/query-core'\nimport { useQueryClient } from './QueryClientProvider'\nimport type {\n Mutation,\n MutationCache,\n MutationFilters,\n MutationState,\n QueryClient,\n} from '@tanstack/query-core'\n\nexport function useIsMutating(\n filters?: MutationFilters,\n queryClient?: QueryClient,\n): number {\n const client = useQueryClient(queryClient)\n return useMutationState(\n { filters: { ...filters, status: 'pending' } },\n client,\n ).length\n}\n\ntype MutationStateOptions = {\n filters?: MutationFilters\n select?: (mutation: Mutation) => TResult\n}\n\nfunction getResult(\n mutationCache: MutationCache,\n options: MutationStateOptions,\n): Array {\n return mutationCache\n .findAll(options.filters)\n .map(\n (mutation): TResult =>\n (options.select ? options.select(mutation) : mutation.state) as TResult,\n )\n}\n\nexport function useMutationState(\n options: MutationStateOptions = {},\n queryClient?: QueryClient,\n): Array {\n const mutationCache = useQueryClient(queryClient).getMutationCache()\n const optionsRef = React.useRef(options)\n const result = React.useRef>(null)\n if (!result.current) {\n result.current = getResult(mutationCache, options)\n }\n\n React.useEffect(() => {\n optionsRef.current = options\n })\n\n return useSyncExternalStore(\n React.useCallback(\n (onStoreChange) =>\n mutationCache.subscribe(() => {\n const nextResult = replaceEqualDeep(\n result.current,\n getResult(mutationCache, optionsRef.current),\n )\n if (result.current !== nextResult) {\n result.current = nextResult\n notifyManager.schedule(onStoreChange)\n }\n }),\n [mutationCache],\n ),\n () => result.current,\n () => result.current,\n )!\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAGA,YAAuB;AACvB,kBAAqC;AAErC,wBAAgD;AAChD,iCAA+B;AASxB,SAAS,cACd,SACA,aACQ;AACR,QAAM,aAAS,2CAAe,WAAW;AACzC,SAAO;AAAA,IACL,EAAE,SAAS,EAAE,GAAG,SAAS,QAAQ,UAAU,EAAE;AAAA,IAC7C;AAAA,EACF,EAAE;AACJ;AAOA,SAAS,UACP,eACA,SACgB;AAChB,SAAO,cACJ,QAAQ,QAAQ,OAAO,EACvB;AAAA,IACC,CAAC,aACE,QAAQ,SAAS,QAAQ,OAAO,QAAQ,IAAI,SAAS;AAAA,EAC1D;AACJ;AAEO,SAAS,iBACd,UAAyC,CAAC,GAC1C,aACgB;AAChB,QAAM,oBAAgB,2CAAe,WAAW,EAAE,iBAAiB;AACnE,QAAM,aAAmB,aAAO,OAAO;AACvC,QAAM,SAAe,aAAuB,IAAI;AAChD,MAAI,CAAC,OAAO,SAAS;AACnB,WAAO,UAAU,UAAU,eAAe,OAAO;AAAA,EACnD;AAEA,EAAM,gBAAU,MAAM;AACpB,eAAW,UAAU;AAAA,EACvB,CAAC;AAED,aAAO;AAAA,IACC;AAAA,MACJ,CAAC,kBACC,cAAc,UAAU,MAAM;AAC5B,cAAM,iBAAa;AAAA,UACjB,OAAO;AAAA,UACP,UAAU,eAAe,WAAW,OAAO;AAAA,QAC7C;AACA,YAAI,OAAO,YAAY,YAAY;AACjC,iBAAO,UAAU;AACjB,0CAAc,SAAS,aAAa;AAAA,QACtC;AAAA,MACF,CAAC;AAAA,MACH,CAAC,aAAa;AAAA,IAChB;AAAA,IACA,MAAM,OAAO;AAAA,IACb,MAAM,OAAO;AAAA,EACf;AACF;","names":[]} +\ No newline at end of file +diff --git a/build/legacy/useMutationState.js b/build/legacy/useMutationState.js +index 0648af4cfd70499f3365abc8b63a06e06976f793..2345f0eecff02f33f0354832b94ce0fdfa31540e 100644 +--- a/build/legacy/useMutationState.js ++++ b/build/legacy/useMutationState.js +@@ -2,6 +2,7 @@ + + // src/useMutationState.ts + import * as React from "react"; ++import { useSyncExternalStore } from "use-sync-external-store/shim/index.js"; + import { notifyManager, replaceEqualDeep } from "@tanstack/query-core"; + import { useQueryClient } from "./QueryClientProvider.js"; + function useIsMutating(filters, queryClient) { +@@ -26,7 +27,7 @@ function useMutationState(options = {}, queryClient) { + React.useEffect(() => { + optionsRef.current = options; + }); +- return React.useSyncExternalStore( ++ return useSyncExternalStore( + React.useCallback( + (onStoreChange) => mutationCache.subscribe(() => { + const nextResult = replaceEqualDeep( +diff --git a/build/legacy/useMutationState.js.map b/build/legacy/useMutationState.js.map +index ae13415e7f9c31177b3ccd37a92ba91b10385705..aa4027b3c846be5f0f769339aee4ff1ac2c0de82 100644 +--- a/build/legacy/useMutationState.js.map ++++ b/build/legacy/useMutationState.js.map +@@ -1 +1 @@ +-{"version":3,"sources":["../../src/useMutationState.ts"],"sourcesContent":["/* eslint-disable react-compiler/react-compiler */\n\n'use client'\nimport * as React from 'react'\n\nimport { notifyManager, replaceEqualDeep } from '@tanstack/query-core'\nimport { useQueryClient } from './QueryClientProvider'\nimport type {\n Mutation,\n MutationCache,\n MutationFilters,\n MutationState,\n QueryClient,\n} from '@tanstack/query-core'\n\nexport function useIsMutating(\n filters?: MutationFilters,\n queryClient?: QueryClient,\n): number {\n const client = useQueryClient(queryClient)\n return useMutationState(\n { filters: { ...filters, status: 'pending' } },\n client,\n ).length\n}\n\ntype MutationStateOptions = {\n filters?: MutationFilters\n select?: (mutation: Mutation) => TResult\n}\n\nfunction getResult(\n mutationCache: MutationCache,\n options: MutationStateOptions,\n): Array {\n return mutationCache\n .findAll(options.filters)\n .map(\n (mutation): TResult =>\n (options.select ? options.select(mutation) : mutation.state) as TResult,\n )\n}\n\nexport function useMutationState(\n options: MutationStateOptions = {},\n queryClient?: QueryClient,\n): Array {\n const mutationCache = useQueryClient(queryClient).getMutationCache()\n const optionsRef = React.useRef(options)\n const result = React.useRef>(null)\n if (!result.current) {\n result.current = getResult(mutationCache, options)\n }\n\n React.useEffect(() => {\n optionsRef.current = options\n })\n\n return React.useSyncExternalStore(\n React.useCallback(\n (onStoreChange) =>\n mutationCache.subscribe(() => {\n const nextResult = replaceEqualDeep(\n result.current,\n getResult(mutationCache, optionsRef.current),\n )\n if (result.current !== nextResult) {\n result.current = nextResult\n notifyManager.schedule(onStoreChange)\n }\n }),\n [mutationCache],\n ),\n () => result.current,\n () => result.current,\n )!\n}\n"],"mappings":";;;AAGA,YAAY,WAAW;AAEvB,SAAS,eAAe,wBAAwB;AAChD,SAAS,sBAAsB;AASxB,SAAS,cACd,SACA,aACQ;AACR,QAAM,SAAS,eAAe,WAAW;AACzC,SAAO;AAAA,IACL,EAAE,SAAS,EAAE,GAAG,SAAS,QAAQ,UAAU,EAAE;AAAA,IAC7C;AAAA,EACF,EAAE;AACJ;AAOA,SAAS,UACP,eACA,SACgB;AAChB,SAAO,cACJ,QAAQ,QAAQ,OAAO,EACvB;AAAA,IACC,CAAC,aACE,QAAQ,SAAS,QAAQ,OAAO,QAAQ,IAAI,SAAS;AAAA,EAC1D;AACJ;AAEO,SAAS,iBACd,UAAyC,CAAC,GAC1C,aACgB;AAChB,QAAM,gBAAgB,eAAe,WAAW,EAAE,iBAAiB;AACnE,QAAM,aAAmB,aAAO,OAAO;AACvC,QAAM,SAAe,aAAuB,IAAI;AAChD,MAAI,CAAC,OAAO,SAAS;AACnB,WAAO,UAAU,UAAU,eAAe,OAAO;AAAA,EACnD;AAEA,EAAM,gBAAU,MAAM;AACpB,eAAW,UAAU;AAAA,EACvB,CAAC;AAED,SAAa;AAAA,IACL;AAAA,MACJ,CAAC,kBACC,cAAc,UAAU,MAAM;AAC5B,cAAM,aAAa;AAAA,UACjB,OAAO;AAAA,UACP,UAAU,eAAe,WAAW,OAAO;AAAA,QAC7C;AACA,YAAI,OAAO,YAAY,YAAY;AACjC,iBAAO,UAAU;AACjB,wBAAc,SAAS,aAAa;AAAA,QACtC;AAAA,MACF,CAAC;AAAA,MACH,CAAC,aAAa;AAAA,IAChB;AAAA,IACA,MAAM,OAAO;AAAA,IACb,MAAM,OAAO;AAAA,EACf;AACF;","names":[]} +\ No newline at end of file ++{"version":3,"sources":["../../src/useMutationState.ts"],"sourcesContent":["/* eslint-disable react-compiler/react-compiler */\n\n'use client'\nimport * as React from 'react'\nimport { useSyncExternalStore } from 'use-sync-external-store/shim/index.js'\n\nimport { notifyManager, replaceEqualDeep } from '@tanstack/query-core'\nimport { useQueryClient } from './QueryClientProvider'\nimport type {\n Mutation,\n MutationCache,\n MutationFilters,\n MutationState,\n QueryClient,\n} from '@tanstack/query-core'\n\nexport function useIsMutating(\n filters?: MutationFilters,\n queryClient?: QueryClient,\n): number {\n const client = useQueryClient(queryClient)\n return useMutationState(\n { filters: { ...filters, status: 'pending' } },\n client,\n ).length\n}\n\ntype MutationStateOptions = {\n filters?: MutationFilters\n select?: (mutation: Mutation) => TResult\n}\n\nfunction getResult(\n mutationCache: MutationCache,\n options: MutationStateOptions,\n): Array {\n return mutationCache\n .findAll(options.filters)\n .map(\n (mutation): TResult =>\n (options.select ? options.select(mutation) : mutation.state) as TResult,\n )\n}\n\nexport function useMutationState(\n options: MutationStateOptions = {},\n queryClient?: QueryClient,\n): Array {\n const mutationCache = useQueryClient(queryClient).getMutationCache()\n const optionsRef = React.useRef(options)\n const result = React.useRef>(null)\n if (!result.current) {\n result.current = getResult(mutationCache, options)\n }\n\n React.useEffect(() => {\n optionsRef.current = options\n })\n\n return useSyncExternalStore(\n React.useCallback(\n (onStoreChange) =>\n mutationCache.subscribe(() => {\n const nextResult = replaceEqualDeep(\n result.current,\n getResult(mutationCache, optionsRef.current),\n )\n if (result.current !== nextResult) {\n result.current = nextResult\n notifyManager.schedule(onStoreChange)\n }\n }),\n [mutationCache],\n ),\n () => result.current,\n () => result.current,\n )!\n}\n"],"mappings":";;;AAGA,YAAY,WAAW;AACvB,SAAS,4BAA4B;AAErC,SAAS,eAAe,wBAAwB;AAChD,SAAS,sBAAsB;AASxB,SAAS,cACd,SACA,aACQ;AACR,QAAM,SAAS,eAAe,WAAW;AACzC,SAAO;AAAA,IACL,EAAE,SAAS,EAAE,GAAG,SAAS,QAAQ,UAAU,EAAE;AAAA,IAC7C;AAAA,EACF,EAAE;AACJ;AAOA,SAAS,UACP,eACA,SACgB;AAChB,SAAO,cACJ,QAAQ,QAAQ,OAAO,EACvB;AAAA,IACC,CAAC,aACE,QAAQ,SAAS,QAAQ,OAAO,QAAQ,IAAI,SAAS;AAAA,EAC1D;AACJ;AAEO,SAAS,iBACd,UAAyC,CAAC,GAC1C,aACgB;AAChB,QAAM,gBAAgB,eAAe,WAAW,EAAE,iBAAiB;AACnE,QAAM,aAAmB,aAAO,OAAO;AACvC,QAAM,SAAe,aAAuB,IAAI;AAChD,MAAI,CAAC,OAAO,SAAS;AACnB,WAAO,UAAU,UAAU,eAAe,OAAO;AAAA,EACnD;AAEA,EAAM,gBAAU,MAAM;AACpB,eAAW,UAAU;AAAA,EACvB,CAAC;AAED,SAAO;AAAA,IACC;AAAA,MACJ,CAAC,kBACC,cAAc,UAAU,MAAM;AAC5B,cAAM,aAAa;AAAA,UACjB,OAAO;AAAA,UACP,UAAU,eAAe,WAAW,OAAO;AAAA,QAC7C;AACA,YAAI,OAAO,YAAY,YAAY;AACjC,iBAAO,UAAU;AACjB,wBAAc,SAAS,aAAa;AAAA,QACtC;AAAA,MACF,CAAC;AAAA,MACH,CAAC,aAAa;AAAA,IAChB;AAAA,IACA,MAAM,OAAO;AAAA,IACb,MAAM,OAAO;AAAA,EACf;AACF;","names":[]} +\ No newline at end of file +diff --git a/build/legacy/useQueries.cjs b/build/legacy/useQueries.cjs +index 30624c08a79ccc7bdb806089683cacf0fd3a7223..03e98d4603058cb15e644a23330ffea99a92b1c8 100644 +--- a/build/legacy/useQueries.cjs ++++ b/build/legacy/useQueries.cjs +@@ -35,6 +35,7 @@ __export(useQueries_exports, { + }); + module.exports = __toCommonJS(useQueries_exports); + var React = __toESM(require("react"), 1); ++var import_shim = require("use-sync-external-store/shim/index.js"); + var import_query_core = require("@tanstack/query-core"); + var import_QueryClientProvider = require("./QueryClientProvider.cjs"); + var import_isRestoring = require("./isRestoring.cjs"); +@@ -75,7 +76,7 @@ function useQueries({ + defaultedQueries, + options.combine + ); +- React.useSyncExternalStore( ++ (0, import_shim.useSyncExternalStore)( + React.useCallback( + (onStoreChange) => isRestoring ? import_utils.noop : observer.subscribe(import_query_core.notifyManager.batchCalls(onStoreChange)), + [observer, isRestoring] +diff --git a/build/legacy/useQueries.cjs.map b/build/legacy/useQueries.cjs.map +index 7b475fbe921935d164f0d29821f068d25281b048..cf2556492a71ceff6c8acfc5ddec4a833de75de7 100644 +--- a/build/legacy/useQueries.cjs.map ++++ b/build/legacy/useQueries.cjs.map +@@ -1 +1 @@ +-{"version":3,"sources":["../../src/useQueries.ts"],"sourcesContent":["'use client'\nimport * as React from 'react'\n\nimport {\n QueriesObserver,\n QueryObserver,\n notifyManager,\n} from '@tanstack/query-core'\nimport { useQueryClient } from './QueryClientProvider'\nimport { useIsRestoring } from './isRestoring'\nimport { useQueryErrorResetBoundary } from './QueryErrorResetBoundary'\nimport {\n ensurePreventErrorBoundaryRetry,\n getHasError,\n useClearResetErrorBoundary,\n} from './errorBoundaryUtils'\nimport {\n ensureSuspenseTimers,\n fetchOptimistic,\n shouldSuspend,\n willFetch,\n} from './suspense'\nimport { noop } from './utils'\nimport type {\n DefinedUseQueryResult,\n UseQueryOptions,\n UseQueryResult,\n} from './types'\nimport type {\n DefaultError,\n OmitKeyof,\n QueriesObserverOptions,\n QueriesPlaceholderDataFunction,\n QueryClient,\n QueryFunction,\n QueryKey,\n QueryObserverOptions,\n ThrowOnError,\n} from '@tanstack/query-core'\n\n// This defines the `UseQueryOptions` that are accepted in `QueriesOptions` & `GetOptions`.\n// `placeholderData` function always gets undefined passed\ntype UseQueryOptionsForUseQueries<\n TQueryFnData = unknown,\n TError = DefaultError,\n TData = TQueryFnData,\n TQueryKey extends QueryKey = QueryKey,\n> = OmitKeyof<\n UseQueryOptions,\n 'placeholderData'\n> & {\n placeholderData?: TQueryFnData | QueriesPlaceholderDataFunction\n}\n\n// Avoid TS depth-limit error in case of large array literal\ntype MAXIMUM_DEPTH = 20\n\n// Widen the type of the symbol to enable type inference even if skipToken is not immutable.\ntype SkipTokenForUseQueries = symbol\n\ntype GetUseQueryOptionsForUseQueries =\n // Part 1: responsible for applying explicit type parameter to function arguments, if object { queryFnData: TQueryFnData, error: TError, data: TData }\n T extends {\n queryFnData: infer TQueryFnData\n error?: infer TError\n data: infer TData\n }\n ? UseQueryOptionsForUseQueries\n : T extends { queryFnData: infer TQueryFnData; error?: infer TError }\n ? UseQueryOptionsForUseQueries\n : T extends { data: infer TData; error?: infer TError }\n ? UseQueryOptionsForUseQueries\n : // Part 2: responsible for applying explicit type parameter to function arguments, if tuple [TQueryFnData, TError, TData]\n T extends [infer TQueryFnData, infer TError, infer TData]\n ? UseQueryOptionsForUseQueries\n : T extends [infer TQueryFnData, infer TError]\n ? UseQueryOptionsForUseQueries\n : T extends [infer TQueryFnData]\n ? UseQueryOptionsForUseQueries\n : // Part 3: responsible for inferring and enforcing type if no explicit parameter was provided\n T extends {\n queryFn?:\n | QueryFunction\n | SkipTokenForUseQueries\n select?: (data: any) => infer TData\n throwOnError?: ThrowOnError\n }\n ? UseQueryOptionsForUseQueries<\n TQueryFnData,\n unknown extends TError ? DefaultError : TError,\n unknown extends TData ? TQueryFnData : TData,\n TQueryKey\n >\n : // Fallback\n UseQueryOptionsForUseQueries\n\n// A defined initialData setting should return a DefinedUseQueryResult rather than UseQueryResult\ntype GetDefinedOrUndefinedQueryResult = T extends {\n initialData?: infer TInitialData\n}\n ? unknown extends TInitialData\n ? UseQueryResult\n : TInitialData extends TData\n ? DefinedUseQueryResult\n : TInitialData extends () => infer TInitialDataResult\n ? unknown extends TInitialDataResult\n ? UseQueryResult\n : TInitialDataResult extends TData\n ? DefinedUseQueryResult\n : UseQueryResult\n : UseQueryResult\n : UseQueryResult\n\ntype GetUseQueryResult =\n // Part 1: responsible for mapping explicit type parameter to function result, if object\n T extends { queryFnData: any; error?: infer TError; data: infer TData }\n ? GetDefinedOrUndefinedQueryResult\n : T extends { queryFnData: infer TQueryFnData; error?: infer TError }\n ? GetDefinedOrUndefinedQueryResult\n : T extends { data: infer TData; error?: infer TError }\n ? GetDefinedOrUndefinedQueryResult\n : // Part 2: responsible for mapping explicit type parameter to function result, if tuple\n T extends [any, infer TError, infer TData]\n ? GetDefinedOrUndefinedQueryResult\n : T extends [infer TQueryFnData, infer TError]\n ? GetDefinedOrUndefinedQueryResult\n : T extends [infer TQueryFnData]\n ? GetDefinedOrUndefinedQueryResult\n : // Part 3: responsible for mapping inferred type to results, if no explicit parameter was provided\n T extends {\n queryFn?:\n | QueryFunction\n | SkipTokenForUseQueries\n select?: (data: any) => infer TData\n throwOnError?: ThrowOnError\n }\n ? GetDefinedOrUndefinedQueryResult<\n T,\n unknown extends TData ? TQueryFnData : TData,\n unknown extends TError ? DefaultError : TError\n >\n : // Fallback\n UseQueryResult\n\n/**\n * QueriesOptions reducer recursively unwraps function arguments to infer/enforce type param\n */\nexport type QueriesOptions<\n T extends Array,\n TResults extends Array = [],\n TDepth extends ReadonlyArray = [],\n> = TDepth['length'] extends MAXIMUM_DEPTH\n ? Array\n : T extends []\n ? []\n : T extends [infer Head]\n ? [...TResults, GetUseQueryOptionsForUseQueries]\n : T extends [infer Head, ...infer Tails]\n ? QueriesOptions<\n [...Tails],\n [...TResults, GetUseQueryOptionsForUseQueries],\n [...TDepth, 1]\n >\n : ReadonlyArray extends T\n ? T\n : // If T is *some* array but we couldn't assign unknown[] to it, then it must hold some known/homogenous type!\n // use this to infer the param types in the case of Array.map() argument\n T extends Array<\n UseQueryOptionsForUseQueries<\n infer TQueryFnData,\n infer TError,\n infer TData,\n infer TQueryKey\n >\n >\n ? Array<\n UseQueryOptionsForUseQueries<\n TQueryFnData,\n TError,\n TData,\n TQueryKey\n >\n >\n : // Fallback\n Array\n\n/**\n * QueriesResults reducer recursively maps type param to results\n */\nexport type QueriesResults<\n T extends Array,\n TResults extends Array = [],\n TDepth extends ReadonlyArray = [],\n> = TDepth['length'] extends MAXIMUM_DEPTH\n ? Array\n : T extends []\n ? []\n : T extends [infer Head]\n ? [...TResults, GetUseQueryResult]\n : T extends [infer Head, ...infer Tails]\n ? QueriesResults<\n [...Tails],\n [...TResults, GetUseQueryResult],\n [...TDepth, 1]\n >\n : T extends Array<\n UseQueryOptionsForUseQueries<\n infer TQueryFnData,\n infer TError,\n infer TData,\n any\n >\n >\n ? // Dynamic-size (homogenous) UseQueryOptions array: map directly to array of results\n Array<\n UseQueryResult<\n unknown extends TData ? TQueryFnData : TData,\n unknown extends TError ? DefaultError : TError\n >\n >\n : // Fallback\n Array\n\nexport function useQueries<\n T extends Array,\n TCombinedResult = QueriesResults,\n>(\n {\n queries,\n ...options\n }: {\n queries: readonly [...QueriesOptions]\n combine?: (result: QueriesResults) => TCombinedResult\n },\n queryClient?: QueryClient,\n): TCombinedResult {\n const client = useQueryClient(queryClient)\n const isRestoring = useIsRestoring()\n const errorResetBoundary = useQueryErrorResetBoundary()\n\n const defaultedQueries = React.useMemo(\n () =>\n queries.map((opts) => {\n const defaultedOptions = client.defaultQueryOptions(\n opts as QueryObserverOptions,\n )\n\n // Make sure the results are already in fetching state before subscribing or updating options\n defaultedOptions._optimisticResults = isRestoring\n ? 'isRestoring'\n : 'optimistic'\n\n return defaultedOptions\n }),\n [queries, client, isRestoring],\n )\n\n defaultedQueries.forEach((query) => {\n ensureSuspenseTimers(query)\n ensurePreventErrorBoundaryRetry(query, errorResetBoundary)\n })\n\n useClearResetErrorBoundary(errorResetBoundary)\n\n const [observer] = React.useState(\n () =>\n new QueriesObserver(\n client,\n defaultedQueries,\n options as QueriesObserverOptions,\n ),\n )\n\n const [optimisticResult, getCombinedResult, trackResult] =\n observer.getOptimisticResult(\n defaultedQueries,\n (options as QueriesObserverOptions).combine,\n )\n\n React.useSyncExternalStore(\n React.useCallback(\n (onStoreChange) =>\n isRestoring\n ? noop\n : observer.subscribe(notifyManager.batchCalls(onStoreChange)),\n [observer, isRestoring],\n ),\n () => observer.getCurrentResult(),\n () => observer.getCurrentResult(),\n )\n\n React.useEffect(() => {\n // Do not notify on updates because of changes in the options because\n // these changes should already be reflected in the optimistic result.\n observer.setQueries(\n defaultedQueries,\n options as QueriesObserverOptions,\n {\n listeners: false,\n },\n )\n }, [defaultedQueries, options, observer])\n\n const shouldAtLeastOneSuspend = optimisticResult.some((result, index) =>\n shouldSuspend(defaultedQueries[index], result),\n )\n\n const suspensePromises = shouldAtLeastOneSuspend\n ? optimisticResult.flatMap((result, index) => {\n const opts = defaultedQueries[index]\n\n if (opts) {\n const queryObserver = new QueryObserver(client, opts)\n if (shouldSuspend(opts, result)) {\n return fetchOptimistic(opts, queryObserver, errorResetBoundary)\n } else if (willFetch(result, isRestoring)) {\n void fetchOptimistic(opts, queryObserver, errorResetBoundary)\n }\n }\n return []\n })\n : []\n\n if (suspensePromises.length > 0) {\n throw Promise.all(suspensePromises)\n }\n const firstSingleResultWhichShouldThrow = optimisticResult.find(\n (result, index) => {\n const query = defaultedQueries[index]\n return (\n query &&\n getHasError({\n result,\n errorResetBoundary,\n throwOnError: query.throwOnError,\n query: client.getQueryCache().get(query.queryHash),\n })\n )\n },\n )\n\n if (firstSingleResultWhichShouldThrow?.error) {\n throw firstSingleResultWhichShouldThrow.error\n }\n\n return getCombinedResult(trackResult())\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AACA,YAAuB;AAEvB,wBAIO;AACP,iCAA+B;AAC/B,yBAA+B;AAC/B,qCAA2C;AAC3C,gCAIO;AACP,sBAKO;AACP,mBAAqB;AAyMd,SAAS,WAId;AAAA,EACE;AAAA,EACA,GAAG;AACL,GAIA,aACiB;AACjB,QAAM,aAAS,2CAAe,WAAW;AACzC,QAAM,kBAAc,mCAAe;AACnC,QAAM,yBAAqB,2DAA2B;AAEtD,QAAM,mBAAyB;AAAA,IAC7B,MACE,QAAQ,IAAI,CAAC,SAAS;AACpB,YAAM,mBAAmB,OAAO;AAAA,QAC9B;AAAA,MACF;AAGA,uBAAiB,qBAAqB,cAClC,gBACA;AAEJ,aAAO;AAAA,IACT,CAAC;AAAA,IACH,CAAC,SAAS,QAAQ,WAAW;AAAA,EAC/B;AAEA,mBAAiB,QAAQ,CAAC,UAAU;AAClC,8CAAqB,KAAK;AAC1B,mEAAgC,OAAO,kBAAkB;AAAA,EAC3D,CAAC;AAED,4DAA2B,kBAAkB;AAE7C,QAAM,CAAC,QAAQ,IAAU;AAAA,IACvB,MACE,IAAI;AAAA,MACF;AAAA,MACA;AAAA,MACA;AAAA,IACF;AAAA,EACJ;AAEA,QAAM,CAAC,kBAAkB,mBAAmB,WAAW,IACrD,SAAS;AAAA,IACP;AAAA,IACC,QAAoD;AAAA,EACvD;AAEF,EAAM;AAAA,IACE;AAAA,MACJ,CAAC,kBACC,cACI,oBACA,SAAS,UAAU,gCAAc,WAAW,aAAa,CAAC;AAAA,MAChE,CAAC,UAAU,WAAW;AAAA,IACxB;AAAA,IACA,MAAM,SAAS,iBAAiB;AAAA,IAChC,MAAM,SAAS,iBAAiB;AAAA,EAClC;AAEA,EAAM,gBAAU,MAAM;AAGpB,aAAS;AAAA,MACP;AAAA,MACA;AAAA,MACA;AAAA,QACE,WAAW;AAAA,MACb;AAAA,IACF;AAAA,EACF,GAAG,CAAC,kBAAkB,SAAS,QAAQ,CAAC;AAExC,QAAM,0BAA0B,iBAAiB;AAAA,IAAK,CAAC,QAAQ,cAC7D,+BAAc,iBAAiB,KAAK,GAAG,MAAM;AAAA,EAC/C;AAEA,QAAM,mBAAmB,0BACrB,iBAAiB,QAAQ,CAAC,QAAQ,UAAU;AAC1C,UAAM,OAAO,iBAAiB,KAAK;AAEnC,QAAI,MAAM;AACR,YAAM,gBAAgB,IAAI,gCAAc,QAAQ,IAAI;AACpD,cAAI,+BAAc,MAAM,MAAM,GAAG;AAC/B,mBAAO,iCAAgB,MAAM,eAAe,kBAAkB;AAAA,MAChE,eAAW,2BAAU,QAAQ,WAAW,GAAG;AACzC,iBAAK,iCAAgB,MAAM,eAAe,kBAAkB;AAAA,MAC9D;AAAA,IACF;AACA,WAAO,CAAC;AAAA,EACV,CAAC,IACD,CAAC;AAEL,MAAI,iBAAiB,SAAS,GAAG;AAC/B,UAAM,QAAQ,IAAI,gBAAgB;AAAA,EACpC;AACA,QAAM,oCAAoC,iBAAiB;AAAA,IACzD,CAAC,QAAQ,UAAU;AACjB,YAAM,QAAQ,iBAAiB,KAAK;AACpC,aACE,aACA,uCAAY;AAAA,QACV;AAAA,QACA;AAAA,QACA,cAAc,MAAM;AAAA,QACpB,OAAO,OAAO,cAAc,EAAE,IAAI,MAAM,SAAS;AAAA,MACnD,CAAC;AAAA,IAEL;AAAA,EACF;AAEA,MAAI,uFAAmC,OAAO;AAC5C,UAAM,kCAAkC;AAAA,EAC1C;AAEA,SAAO,kBAAkB,YAAY,CAAC;AACxC;","names":[]} +\ No newline at end of file ++{"version":3,"sources":["../../src/useQueries.ts"],"sourcesContent":["'use client'\nimport * as React from 'react'\nimport { useSyncExternalStore } from 'use-sync-external-store/shim/index.js'\n\nimport {\n QueriesObserver,\n QueryObserver,\n notifyManager,\n} from '@tanstack/query-core'\nimport { useQueryClient } from './QueryClientProvider'\nimport { useIsRestoring } from './isRestoring'\nimport { useQueryErrorResetBoundary } from './QueryErrorResetBoundary'\nimport {\n ensurePreventErrorBoundaryRetry,\n getHasError,\n useClearResetErrorBoundary,\n} from './errorBoundaryUtils'\nimport {\n ensureSuspenseTimers,\n fetchOptimistic,\n shouldSuspend,\n willFetch,\n} from './suspense'\nimport { noop } from './utils'\nimport type {\n DefinedUseQueryResult,\n UseQueryOptions,\n UseQueryResult,\n} from './types'\nimport type {\n DefaultError,\n OmitKeyof,\n QueriesObserverOptions,\n QueriesPlaceholderDataFunction,\n QueryClient,\n QueryFunction,\n QueryKey,\n QueryObserverOptions,\n ThrowOnError,\n} from '@tanstack/query-core'\n\n// This defines the `UseQueryOptions` that are accepted in `QueriesOptions` & `GetOptions`.\n// `placeholderData` function always gets undefined passed\ntype UseQueryOptionsForUseQueries<\n TQueryFnData = unknown,\n TError = DefaultError,\n TData = TQueryFnData,\n TQueryKey extends QueryKey = QueryKey,\n> = OmitKeyof<\n UseQueryOptions,\n 'placeholderData'\n> & {\n placeholderData?: TQueryFnData | QueriesPlaceholderDataFunction\n}\n\n// Avoid TS depth-limit error in case of large array literal\ntype MAXIMUM_DEPTH = 20\n\n// Widen the type of the symbol to enable type inference even if skipToken is not immutable.\ntype SkipTokenForUseQueries = symbol\n\ntype GetUseQueryOptionsForUseQueries =\n // Part 1: responsible for applying explicit type parameter to function arguments, if object { queryFnData: TQueryFnData, error: TError, data: TData }\n T extends {\n queryFnData: infer TQueryFnData\n error?: infer TError\n data: infer TData\n }\n ? UseQueryOptionsForUseQueries\n : T extends { queryFnData: infer TQueryFnData; error?: infer TError }\n ? UseQueryOptionsForUseQueries\n : T extends { data: infer TData; error?: infer TError }\n ? UseQueryOptionsForUseQueries\n : // Part 2: responsible for applying explicit type parameter to function arguments, if tuple [TQueryFnData, TError, TData]\n T extends [infer TQueryFnData, infer TError, infer TData]\n ? UseQueryOptionsForUseQueries\n : T extends [infer TQueryFnData, infer TError]\n ? UseQueryOptionsForUseQueries\n : T extends [infer TQueryFnData]\n ? UseQueryOptionsForUseQueries\n : // Part 3: responsible for inferring and enforcing type if no explicit parameter was provided\n T extends {\n queryFn?:\n | QueryFunction\n | SkipTokenForUseQueries\n select?: (data: any) => infer TData\n throwOnError?: ThrowOnError\n }\n ? UseQueryOptionsForUseQueries<\n TQueryFnData,\n unknown extends TError ? DefaultError : TError,\n unknown extends TData ? TQueryFnData : TData,\n TQueryKey\n >\n : // Fallback\n UseQueryOptionsForUseQueries\n\n// A defined initialData setting should return a DefinedUseQueryResult rather than UseQueryResult\ntype GetDefinedOrUndefinedQueryResult = T extends {\n initialData?: infer TInitialData\n}\n ? unknown extends TInitialData\n ? UseQueryResult\n : TInitialData extends TData\n ? DefinedUseQueryResult\n : TInitialData extends () => infer TInitialDataResult\n ? unknown extends TInitialDataResult\n ? UseQueryResult\n : TInitialDataResult extends TData\n ? DefinedUseQueryResult\n : UseQueryResult\n : UseQueryResult\n : UseQueryResult\n\ntype GetUseQueryResult =\n // Part 1: responsible for mapping explicit type parameter to function result, if object\n T extends { queryFnData: any; error?: infer TError; data: infer TData }\n ? GetDefinedOrUndefinedQueryResult\n : T extends { queryFnData: infer TQueryFnData; error?: infer TError }\n ? GetDefinedOrUndefinedQueryResult\n : T extends { data: infer TData; error?: infer TError }\n ? GetDefinedOrUndefinedQueryResult\n : // Part 2: responsible for mapping explicit type parameter to function result, if tuple\n T extends [any, infer TError, infer TData]\n ? GetDefinedOrUndefinedQueryResult\n : T extends [infer TQueryFnData, infer TError]\n ? GetDefinedOrUndefinedQueryResult\n : T extends [infer TQueryFnData]\n ? GetDefinedOrUndefinedQueryResult\n : // Part 3: responsible for mapping inferred type to results, if no explicit parameter was provided\n T extends {\n queryFn?:\n | QueryFunction\n | SkipTokenForUseQueries\n select?: (data: any) => infer TData\n throwOnError?: ThrowOnError\n }\n ? GetDefinedOrUndefinedQueryResult<\n T,\n unknown extends TData ? TQueryFnData : TData,\n unknown extends TError ? DefaultError : TError\n >\n : // Fallback\n UseQueryResult\n\n/**\n * QueriesOptions reducer recursively unwraps function arguments to infer/enforce type param\n */\nexport type QueriesOptions<\n T extends Array,\n TResults extends Array = [],\n TDepth extends ReadonlyArray = [],\n> = TDepth['length'] extends MAXIMUM_DEPTH\n ? Array\n : T extends []\n ? []\n : T extends [infer Head]\n ? [...TResults, GetUseQueryOptionsForUseQueries]\n : T extends [infer Head, ...infer Tails]\n ? QueriesOptions<\n [...Tails],\n [...TResults, GetUseQueryOptionsForUseQueries],\n [...TDepth, 1]\n >\n : ReadonlyArray extends T\n ? T\n : // If T is *some* array but we couldn't assign unknown[] to it, then it must hold some known/homogenous type!\n // use this to infer the param types in the case of Array.map() argument\n T extends Array<\n UseQueryOptionsForUseQueries<\n infer TQueryFnData,\n infer TError,\n infer TData,\n infer TQueryKey\n >\n >\n ? Array<\n UseQueryOptionsForUseQueries<\n TQueryFnData,\n TError,\n TData,\n TQueryKey\n >\n >\n : // Fallback\n Array\n\n/**\n * QueriesResults reducer recursively maps type param to results\n */\nexport type QueriesResults<\n T extends Array,\n TResults extends Array = [],\n TDepth extends ReadonlyArray = [],\n> = TDepth['length'] extends MAXIMUM_DEPTH\n ? Array\n : T extends []\n ? []\n : T extends [infer Head]\n ? [...TResults, GetUseQueryResult]\n : T extends [infer Head, ...infer Tails]\n ? QueriesResults<\n [...Tails],\n [...TResults, GetUseQueryResult],\n [...TDepth, 1]\n >\n : T extends Array<\n UseQueryOptionsForUseQueries<\n infer TQueryFnData,\n infer TError,\n infer TData,\n any\n >\n >\n ? // Dynamic-size (homogenous) UseQueryOptions array: map directly to array of results\n Array<\n UseQueryResult<\n unknown extends TData ? TQueryFnData : TData,\n unknown extends TError ? DefaultError : TError\n >\n >\n : // Fallback\n Array\n\nexport function useQueries<\n T extends Array,\n TCombinedResult = QueriesResults,\n>(\n {\n queries,\n ...options\n }: {\n queries: readonly [...QueriesOptions]\n combine?: (result: QueriesResults) => TCombinedResult\n },\n queryClient?: QueryClient,\n): TCombinedResult {\n const client = useQueryClient(queryClient)\n const isRestoring = useIsRestoring()\n const errorResetBoundary = useQueryErrorResetBoundary()\n\n const defaultedQueries = React.useMemo(\n () =>\n queries.map((opts) => {\n const defaultedOptions = client.defaultQueryOptions(\n opts as QueryObserverOptions,\n )\n\n // Make sure the results are already in fetching state before subscribing or updating options\n defaultedOptions._optimisticResults = isRestoring\n ? 'isRestoring'\n : 'optimistic'\n\n return defaultedOptions\n }),\n [queries, client, isRestoring],\n )\n\n defaultedQueries.forEach((query) => {\n ensureSuspenseTimers(query)\n ensurePreventErrorBoundaryRetry(query, errorResetBoundary)\n })\n\n useClearResetErrorBoundary(errorResetBoundary)\n\n const [observer] = React.useState(\n () =>\n new QueriesObserver(\n client,\n defaultedQueries,\n options as QueriesObserverOptions,\n ),\n )\n\n const [optimisticResult, getCombinedResult, trackResult] =\n observer.getOptimisticResult(\n defaultedQueries,\n (options as QueriesObserverOptions).combine,\n )\n\n useSyncExternalStore(\n React.useCallback(\n (onStoreChange) =>\n isRestoring\n ? noop\n : observer.subscribe(notifyManager.batchCalls(onStoreChange)),\n [observer, isRestoring],\n ),\n () => observer.getCurrentResult(),\n () => observer.getCurrentResult(),\n )\n\n React.useEffect(() => {\n // Do not notify on updates because of changes in the options because\n // these changes should already be reflected in the optimistic result.\n observer.setQueries(\n defaultedQueries,\n options as QueriesObserverOptions,\n {\n listeners: false,\n },\n )\n }, [defaultedQueries, options, observer])\n\n const shouldAtLeastOneSuspend = optimisticResult.some((result, index) =>\n shouldSuspend(defaultedQueries[index], result),\n )\n\n const suspensePromises = shouldAtLeastOneSuspend\n ? optimisticResult.flatMap((result, index) => {\n const opts = defaultedQueries[index]\n\n if (opts) {\n const queryObserver = new QueryObserver(client, opts)\n if (shouldSuspend(opts, result)) {\n return fetchOptimistic(opts, queryObserver, errorResetBoundary)\n } else if (willFetch(result, isRestoring)) {\n void fetchOptimistic(opts, queryObserver, errorResetBoundary)\n }\n }\n return []\n })\n : []\n\n if (suspensePromises.length > 0) {\n throw Promise.all(suspensePromises)\n }\n const firstSingleResultWhichShouldThrow = optimisticResult.find(\n (result, index) => {\n const query = defaultedQueries[index]\n return (\n query &&\n getHasError({\n result,\n errorResetBoundary,\n throwOnError: query.throwOnError,\n query: client.getQueryCache().get(query.queryHash),\n })\n )\n },\n )\n\n if (firstSingleResultWhichShouldThrow?.error) {\n throw firstSingleResultWhichShouldThrow.error\n }\n\n return getCombinedResult(trackResult())\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AACA,YAAuB;AACvB,kBAAqC;AAErC,wBAIO;AACP,iCAA+B;AAC/B,yBAA+B;AAC/B,qCAA2C;AAC3C,gCAIO;AACP,sBAKO;AACP,mBAAqB;AAyMd,SAAS,WAId;AAAA,EACE;AAAA,EACA,GAAG;AACL,GAIA,aACiB;AACjB,QAAM,aAAS,2CAAe,WAAW;AACzC,QAAM,kBAAc,mCAAe;AACnC,QAAM,yBAAqB,2DAA2B;AAEtD,QAAM,mBAAyB;AAAA,IAC7B,MACE,QAAQ,IAAI,CAAC,SAAS;AACpB,YAAM,mBAAmB,OAAO;AAAA,QAC9B;AAAA,MACF;AAGA,uBAAiB,qBAAqB,cAClC,gBACA;AAEJ,aAAO;AAAA,IACT,CAAC;AAAA,IACH,CAAC,SAAS,QAAQ,WAAW;AAAA,EAC/B;AAEA,mBAAiB,QAAQ,CAAC,UAAU;AAClC,8CAAqB,KAAK;AAC1B,mEAAgC,OAAO,kBAAkB;AAAA,EAC3D,CAAC;AAED,4DAA2B,kBAAkB;AAE7C,QAAM,CAAC,QAAQ,IAAU;AAAA,IACvB,MACE,IAAI;AAAA,MACF;AAAA,MACA;AAAA,MACA;AAAA,IACF;AAAA,EACJ;AAEA,QAAM,CAAC,kBAAkB,mBAAmB,WAAW,IACrD,SAAS;AAAA,IACP;AAAA,IACC,QAAoD;AAAA,EACvD;AAEF;AAAA,IACQ;AAAA,MACJ,CAAC,kBACC,cACI,oBACA,SAAS,UAAU,gCAAc,WAAW,aAAa,CAAC;AAAA,MAChE,CAAC,UAAU,WAAW;AAAA,IACxB;AAAA,IACA,MAAM,SAAS,iBAAiB;AAAA,IAChC,MAAM,SAAS,iBAAiB;AAAA,EAClC;AAEA,EAAM,gBAAU,MAAM;AAGpB,aAAS;AAAA,MACP;AAAA,MACA;AAAA,MACA;AAAA,QACE,WAAW;AAAA,MACb;AAAA,IACF;AAAA,EACF,GAAG,CAAC,kBAAkB,SAAS,QAAQ,CAAC;AAExC,QAAM,0BAA0B,iBAAiB;AAAA,IAAK,CAAC,QAAQ,cAC7D,+BAAc,iBAAiB,KAAK,GAAG,MAAM;AAAA,EAC/C;AAEA,QAAM,mBAAmB,0BACrB,iBAAiB,QAAQ,CAAC,QAAQ,UAAU;AAC1C,UAAM,OAAO,iBAAiB,KAAK;AAEnC,QAAI,MAAM;AACR,YAAM,gBAAgB,IAAI,gCAAc,QAAQ,IAAI;AACpD,cAAI,+BAAc,MAAM,MAAM,GAAG;AAC/B,mBAAO,iCAAgB,MAAM,eAAe,kBAAkB;AAAA,MAChE,eAAW,2BAAU,QAAQ,WAAW,GAAG;AACzC,iBAAK,iCAAgB,MAAM,eAAe,kBAAkB;AAAA,MAC9D;AAAA,IACF;AACA,WAAO,CAAC;AAAA,EACV,CAAC,IACD,CAAC;AAEL,MAAI,iBAAiB,SAAS,GAAG;AAC/B,UAAM,QAAQ,IAAI,gBAAgB;AAAA,EACpC;AACA,QAAM,oCAAoC,iBAAiB;AAAA,IACzD,CAAC,QAAQ,UAAU;AACjB,YAAM,QAAQ,iBAAiB,KAAK;AACpC,aACE,aACA,uCAAY;AAAA,QACV;AAAA,QACA;AAAA,QACA,cAAc,MAAM;AAAA,QACpB,OAAO,OAAO,cAAc,EAAE,IAAI,MAAM,SAAS;AAAA,MACnD,CAAC;AAAA,IAEL;AAAA,EACF;AAEA,MAAI,uFAAmC,OAAO;AAC5C,UAAM,kCAAkC;AAAA,EAC1C;AAEA,SAAO,kBAAkB,YAAY,CAAC;AACxC;","names":[]} +\ No newline at end of file +diff --git a/build/legacy/useQueries.js b/build/legacy/useQueries.js +index fe5a1a787a1c9419ba2601dd0e15d738bac0a24b..d440e604085f75127ce7800bf29c10c97df4b319 100644 +--- a/build/legacy/useQueries.js ++++ b/build/legacy/useQueries.js +@@ -2,6 +2,7 @@ + + // src/useQueries.ts + import * as React from "react"; ++import { useSyncExternalStore } from "use-sync-external-store/shim/index.js"; + import { + QueriesObserver, + QueryObserver, +@@ -55,7 +56,7 @@ function useQueries({ + defaultedQueries, + options.combine + ); +- React.useSyncExternalStore( ++ useSyncExternalStore( + React.useCallback( + (onStoreChange) => isRestoring ? noop : observer.subscribe(notifyManager.batchCalls(onStoreChange)), + [observer, isRestoring] +diff --git a/build/legacy/useQueries.js.map b/build/legacy/useQueries.js.map +index b4e19659cea057b7421f374e1a3a45f882225ba2..49c8e1f60074ef0ae796cc179522aa84cabd9e57 100644 +--- a/build/legacy/useQueries.js.map ++++ b/build/legacy/useQueries.js.map +@@ -1 +1 @@ +-{"version":3,"sources":["../../src/useQueries.ts"],"sourcesContent":["'use client'\nimport * as React from 'react'\n\nimport {\n QueriesObserver,\n QueryObserver,\n notifyManager,\n} from '@tanstack/query-core'\nimport { useQueryClient } from './QueryClientProvider'\nimport { useIsRestoring } from './isRestoring'\nimport { useQueryErrorResetBoundary } from './QueryErrorResetBoundary'\nimport {\n ensurePreventErrorBoundaryRetry,\n getHasError,\n useClearResetErrorBoundary,\n} from './errorBoundaryUtils'\nimport {\n ensureSuspenseTimers,\n fetchOptimistic,\n shouldSuspend,\n willFetch,\n} from './suspense'\nimport { noop } from './utils'\nimport type {\n DefinedUseQueryResult,\n UseQueryOptions,\n UseQueryResult,\n} from './types'\nimport type {\n DefaultError,\n OmitKeyof,\n QueriesObserverOptions,\n QueriesPlaceholderDataFunction,\n QueryClient,\n QueryFunction,\n QueryKey,\n QueryObserverOptions,\n ThrowOnError,\n} from '@tanstack/query-core'\n\n// This defines the `UseQueryOptions` that are accepted in `QueriesOptions` & `GetOptions`.\n// `placeholderData` function always gets undefined passed\ntype UseQueryOptionsForUseQueries<\n TQueryFnData = unknown,\n TError = DefaultError,\n TData = TQueryFnData,\n TQueryKey extends QueryKey = QueryKey,\n> = OmitKeyof<\n UseQueryOptions,\n 'placeholderData'\n> & {\n placeholderData?: TQueryFnData | QueriesPlaceholderDataFunction\n}\n\n// Avoid TS depth-limit error in case of large array literal\ntype MAXIMUM_DEPTH = 20\n\n// Widen the type of the symbol to enable type inference even if skipToken is not immutable.\ntype SkipTokenForUseQueries = symbol\n\ntype GetUseQueryOptionsForUseQueries =\n // Part 1: responsible for applying explicit type parameter to function arguments, if object { queryFnData: TQueryFnData, error: TError, data: TData }\n T extends {\n queryFnData: infer TQueryFnData\n error?: infer TError\n data: infer TData\n }\n ? UseQueryOptionsForUseQueries\n : T extends { queryFnData: infer TQueryFnData; error?: infer TError }\n ? UseQueryOptionsForUseQueries\n : T extends { data: infer TData; error?: infer TError }\n ? UseQueryOptionsForUseQueries\n : // Part 2: responsible for applying explicit type parameter to function arguments, if tuple [TQueryFnData, TError, TData]\n T extends [infer TQueryFnData, infer TError, infer TData]\n ? UseQueryOptionsForUseQueries\n : T extends [infer TQueryFnData, infer TError]\n ? UseQueryOptionsForUseQueries\n : T extends [infer TQueryFnData]\n ? UseQueryOptionsForUseQueries\n : // Part 3: responsible for inferring and enforcing type if no explicit parameter was provided\n T extends {\n queryFn?:\n | QueryFunction\n | SkipTokenForUseQueries\n select?: (data: any) => infer TData\n throwOnError?: ThrowOnError\n }\n ? UseQueryOptionsForUseQueries<\n TQueryFnData,\n unknown extends TError ? DefaultError : TError,\n unknown extends TData ? TQueryFnData : TData,\n TQueryKey\n >\n : // Fallback\n UseQueryOptionsForUseQueries\n\n// A defined initialData setting should return a DefinedUseQueryResult rather than UseQueryResult\ntype GetDefinedOrUndefinedQueryResult = T extends {\n initialData?: infer TInitialData\n}\n ? unknown extends TInitialData\n ? UseQueryResult\n : TInitialData extends TData\n ? DefinedUseQueryResult\n : TInitialData extends () => infer TInitialDataResult\n ? unknown extends TInitialDataResult\n ? UseQueryResult\n : TInitialDataResult extends TData\n ? DefinedUseQueryResult\n : UseQueryResult\n : UseQueryResult\n : UseQueryResult\n\ntype GetUseQueryResult =\n // Part 1: responsible for mapping explicit type parameter to function result, if object\n T extends { queryFnData: any; error?: infer TError; data: infer TData }\n ? GetDefinedOrUndefinedQueryResult\n : T extends { queryFnData: infer TQueryFnData; error?: infer TError }\n ? GetDefinedOrUndefinedQueryResult\n : T extends { data: infer TData; error?: infer TError }\n ? GetDefinedOrUndefinedQueryResult\n : // Part 2: responsible for mapping explicit type parameter to function result, if tuple\n T extends [any, infer TError, infer TData]\n ? GetDefinedOrUndefinedQueryResult\n : T extends [infer TQueryFnData, infer TError]\n ? GetDefinedOrUndefinedQueryResult\n : T extends [infer TQueryFnData]\n ? GetDefinedOrUndefinedQueryResult\n : // Part 3: responsible for mapping inferred type to results, if no explicit parameter was provided\n T extends {\n queryFn?:\n | QueryFunction\n | SkipTokenForUseQueries\n select?: (data: any) => infer TData\n throwOnError?: ThrowOnError\n }\n ? GetDefinedOrUndefinedQueryResult<\n T,\n unknown extends TData ? TQueryFnData : TData,\n unknown extends TError ? DefaultError : TError\n >\n : // Fallback\n UseQueryResult\n\n/**\n * QueriesOptions reducer recursively unwraps function arguments to infer/enforce type param\n */\nexport type QueriesOptions<\n T extends Array,\n TResults extends Array = [],\n TDepth extends ReadonlyArray = [],\n> = TDepth['length'] extends MAXIMUM_DEPTH\n ? Array\n : T extends []\n ? []\n : T extends [infer Head]\n ? [...TResults, GetUseQueryOptionsForUseQueries]\n : T extends [infer Head, ...infer Tails]\n ? QueriesOptions<\n [...Tails],\n [...TResults, GetUseQueryOptionsForUseQueries],\n [...TDepth, 1]\n >\n : ReadonlyArray extends T\n ? T\n : // If T is *some* array but we couldn't assign unknown[] to it, then it must hold some known/homogenous type!\n // use this to infer the param types in the case of Array.map() argument\n T extends Array<\n UseQueryOptionsForUseQueries<\n infer TQueryFnData,\n infer TError,\n infer TData,\n infer TQueryKey\n >\n >\n ? Array<\n UseQueryOptionsForUseQueries<\n TQueryFnData,\n TError,\n TData,\n TQueryKey\n >\n >\n : // Fallback\n Array\n\n/**\n * QueriesResults reducer recursively maps type param to results\n */\nexport type QueriesResults<\n T extends Array,\n TResults extends Array = [],\n TDepth extends ReadonlyArray = [],\n> = TDepth['length'] extends MAXIMUM_DEPTH\n ? Array\n : T extends []\n ? []\n : T extends [infer Head]\n ? [...TResults, GetUseQueryResult]\n : T extends [infer Head, ...infer Tails]\n ? QueriesResults<\n [...Tails],\n [...TResults, GetUseQueryResult],\n [...TDepth, 1]\n >\n : T extends Array<\n UseQueryOptionsForUseQueries<\n infer TQueryFnData,\n infer TError,\n infer TData,\n any\n >\n >\n ? // Dynamic-size (homogenous) UseQueryOptions array: map directly to array of results\n Array<\n UseQueryResult<\n unknown extends TData ? TQueryFnData : TData,\n unknown extends TError ? DefaultError : TError\n >\n >\n : // Fallback\n Array\n\nexport function useQueries<\n T extends Array,\n TCombinedResult = QueriesResults,\n>(\n {\n queries,\n ...options\n }: {\n queries: readonly [...QueriesOptions]\n combine?: (result: QueriesResults) => TCombinedResult\n },\n queryClient?: QueryClient,\n): TCombinedResult {\n const client = useQueryClient(queryClient)\n const isRestoring = useIsRestoring()\n const errorResetBoundary = useQueryErrorResetBoundary()\n\n const defaultedQueries = React.useMemo(\n () =>\n queries.map((opts) => {\n const defaultedOptions = client.defaultQueryOptions(\n opts as QueryObserverOptions,\n )\n\n // Make sure the results are already in fetching state before subscribing or updating options\n defaultedOptions._optimisticResults = isRestoring\n ? 'isRestoring'\n : 'optimistic'\n\n return defaultedOptions\n }),\n [queries, client, isRestoring],\n )\n\n defaultedQueries.forEach((query) => {\n ensureSuspenseTimers(query)\n ensurePreventErrorBoundaryRetry(query, errorResetBoundary)\n })\n\n useClearResetErrorBoundary(errorResetBoundary)\n\n const [observer] = React.useState(\n () =>\n new QueriesObserver(\n client,\n defaultedQueries,\n options as QueriesObserverOptions,\n ),\n )\n\n const [optimisticResult, getCombinedResult, trackResult] =\n observer.getOptimisticResult(\n defaultedQueries,\n (options as QueriesObserverOptions).combine,\n )\n\n React.useSyncExternalStore(\n React.useCallback(\n (onStoreChange) =>\n isRestoring\n ? noop\n : observer.subscribe(notifyManager.batchCalls(onStoreChange)),\n [observer, isRestoring],\n ),\n () => observer.getCurrentResult(),\n () => observer.getCurrentResult(),\n )\n\n React.useEffect(() => {\n // Do not notify on updates because of changes in the options because\n // these changes should already be reflected in the optimistic result.\n observer.setQueries(\n defaultedQueries,\n options as QueriesObserverOptions,\n {\n listeners: false,\n },\n )\n }, [defaultedQueries, options, observer])\n\n const shouldAtLeastOneSuspend = optimisticResult.some((result, index) =>\n shouldSuspend(defaultedQueries[index], result),\n )\n\n const suspensePromises = shouldAtLeastOneSuspend\n ? optimisticResult.flatMap((result, index) => {\n const opts = defaultedQueries[index]\n\n if (opts) {\n const queryObserver = new QueryObserver(client, opts)\n if (shouldSuspend(opts, result)) {\n return fetchOptimistic(opts, queryObserver, errorResetBoundary)\n } else if (willFetch(result, isRestoring)) {\n void fetchOptimistic(opts, queryObserver, errorResetBoundary)\n }\n }\n return []\n })\n : []\n\n if (suspensePromises.length > 0) {\n throw Promise.all(suspensePromises)\n }\n const firstSingleResultWhichShouldThrow = optimisticResult.find(\n (result, index) => {\n const query = defaultedQueries[index]\n return (\n query &&\n getHasError({\n result,\n errorResetBoundary,\n throwOnError: query.throwOnError,\n query: client.getQueryCache().get(query.queryHash),\n })\n )\n },\n )\n\n if (firstSingleResultWhichShouldThrow?.error) {\n throw firstSingleResultWhichShouldThrow.error\n }\n\n return getCombinedResult(trackResult())\n}\n"],"mappings":";;;AACA,YAAY,WAAW;AAEvB;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,OACK;AACP,SAAS,sBAAsB;AAC/B,SAAS,sBAAsB;AAC/B,SAAS,kCAAkC;AAC3C;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,OACK;AACP;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OACK;AACP,SAAS,YAAY;AAyMd,SAAS,WAId;AAAA,EACE;AAAA,EACA,GAAG;AACL,GAIA,aACiB;AACjB,QAAM,SAAS,eAAe,WAAW;AACzC,QAAM,cAAc,eAAe;AACnC,QAAM,qBAAqB,2BAA2B;AAEtD,QAAM,mBAAyB;AAAA,IAC7B,MACE,QAAQ,IAAI,CAAC,SAAS;AACpB,YAAM,mBAAmB,OAAO;AAAA,QAC9B;AAAA,MACF;AAGA,uBAAiB,qBAAqB,cAClC,gBACA;AAEJ,aAAO;AAAA,IACT,CAAC;AAAA,IACH,CAAC,SAAS,QAAQ,WAAW;AAAA,EAC/B;AAEA,mBAAiB,QAAQ,CAAC,UAAU;AAClC,yBAAqB,KAAK;AAC1B,oCAAgC,OAAO,kBAAkB;AAAA,EAC3D,CAAC;AAED,6BAA2B,kBAAkB;AAE7C,QAAM,CAAC,QAAQ,IAAU;AAAA,IACvB,MACE,IAAI;AAAA,MACF;AAAA,MACA;AAAA,MACA;AAAA,IACF;AAAA,EACJ;AAEA,QAAM,CAAC,kBAAkB,mBAAmB,WAAW,IACrD,SAAS;AAAA,IACP;AAAA,IACC,QAAoD;AAAA,EACvD;AAEF,EAAM;AAAA,IACE;AAAA,MACJ,CAAC,kBACC,cACI,OACA,SAAS,UAAU,cAAc,WAAW,aAAa,CAAC;AAAA,MAChE,CAAC,UAAU,WAAW;AAAA,IACxB;AAAA,IACA,MAAM,SAAS,iBAAiB;AAAA,IAChC,MAAM,SAAS,iBAAiB;AAAA,EAClC;AAEA,EAAM,gBAAU,MAAM;AAGpB,aAAS;AAAA,MACP;AAAA,MACA;AAAA,MACA;AAAA,QACE,WAAW;AAAA,MACb;AAAA,IACF;AAAA,EACF,GAAG,CAAC,kBAAkB,SAAS,QAAQ,CAAC;AAExC,QAAM,0BAA0B,iBAAiB;AAAA,IAAK,CAAC,QAAQ,UAC7D,cAAc,iBAAiB,KAAK,GAAG,MAAM;AAAA,EAC/C;AAEA,QAAM,mBAAmB,0BACrB,iBAAiB,QAAQ,CAAC,QAAQ,UAAU;AAC1C,UAAM,OAAO,iBAAiB,KAAK;AAEnC,QAAI,MAAM;AACR,YAAM,gBAAgB,IAAI,cAAc,QAAQ,IAAI;AACpD,UAAI,cAAc,MAAM,MAAM,GAAG;AAC/B,eAAO,gBAAgB,MAAM,eAAe,kBAAkB;AAAA,MAChE,WAAW,UAAU,QAAQ,WAAW,GAAG;AACzC,aAAK,gBAAgB,MAAM,eAAe,kBAAkB;AAAA,MAC9D;AAAA,IACF;AACA,WAAO,CAAC;AAAA,EACV,CAAC,IACD,CAAC;AAEL,MAAI,iBAAiB,SAAS,GAAG;AAC/B,UAAM,QAAQ,IAAI,gBAAgB;AAAA,EACpC;AACA,QAAM,oCAAoC,iBAAiB;AAAA,IACzD,CAAC,QAAQ,UAAU;AACjB,YAAM,QAAQ,iBAAiB,KAAK;AACpC,aACE,SACA,YAAY;AAAA,QACV;AAAA,QACA;AAAA,QACA,cAAc,MAAM;AAAA,QACpB,OAAO,OAAO,cAAc,EAAE,IAAI,MAAM,SAAS;AAAA,MACnD,CAAC;AAAA,IAEL;AAAA,EACF;AAEA,MAAI,uFAAmC,OAAO;AAC5C,UAAM,kCAAkC;AAAA,EAC1C;AAEA,SAAO,kBAAkB,YAAY,CAAC;AACxC;","names":[]} +\ No newline at end of file ++{"version":3,"sources":["../../src/useQueries.ts"],"sourcesContent":["'use client'\nimport * as React from 'react'\nimport { useSyncExternalStore } from 'use-sync-external-store/shim/index.js'\n\nimport {\n QueriesObserver,\n QueryObserver,\n notifyManager,\n} from '@tanstack/query-core'\nimport { useQueryClient } from './QueryClientProvider'\nimport { useIsRestoring } from './isRestoring'\nimport { useQueryErrorResetBoundary } from './QueryErrorResetBoundary'\nimport {\n ensurePreventErrorBoundaryRetry,\n getHasError,\n useClearResetErrorBoundary,\n} from './errorBoundaryUtils'\nimport {\n ensureSuspenseTimers,\n fetchOptimistic,\n shouldSuspend,\n willFetch,\n} from './suspense'\nimport { noop } from './utils'\nimport type {\n DefinedUseQueryResult,\n UseQueryOptions,\n UseQueryResult,\n} from './types'\nimport type {\n DefaultError,\n OmitKeyof,\n QueriesObserverOptions,\n QueriesPlaceholderDataFunction,\n QueryClient,\n QueryFunction,\n QueryKey,\n QueryObserverOptions,\n ThrowOnError,\n} from '@tanstack/query-core'\n\n// This defines the `UseQueryOptions` that are accepted in `QueriesOptions` & `GetOptions`.\n// `placeholderData` function always gets undefined passed\ntype UseQueryOptionsForUseQueries<\n TQueryFnData = unknown,\n TError = DefaultError,\n TData = TQueryFnData,\n TQueryKey extends QueryKey = QueryKey,\n> = OmitKeyof<\n UseQueryOptions,\n 'placeholderData'\n> & {\n placeholderData?: TQueryFnData | QueriesPlaceholderDataFunction\n}\n\n// Avoid TS depth-limit error in case of large array literal\ntype MAXIMUM_DEPTH = 20\n\n// Widen the type of the symbol to enable type inference even if skipToken is not immutable.\ntype SkipTokenForUseQueries = symbol\n\ntype GetUseQueryOptionsForUseQueries =\n // Part 1: responsible for applying explicit type parameter to function arguments, if object { queryFnData: TQueryFnData, error: TError, data: TData }\n T extends {\n queryFnData: infer TQueryFnData\n error?: infer TError\n data: infer TData\n }\n ? UseQueryOptionsForUseQueries\n : T extends { queryFnData: infer TQueryFnData; error?: infer TError }\n ? UseQueryOptionsForUseQueries\n : T extends { data: infer TData; error?: infer TError }\n ? UseQueryOptionsForUseQueries\n : // Part 2: responsible for applying explicit type parameter to function arguments, if tuple [TQueryFnData, TError, TData]\n T extends [infer TQueryFnData, infer TError, infer TData]\n ? UseQueryOptionsForUseQueries\n : T extends [infer TQueryFnData, infer TError]\n ? UseQueryOptionsForUseQueries\n : T extends [infer TQueryFnData]\n ? UseQueryOptionsForUseQueries\n : // Part 3: responsible for inferring and enforcing type if no explicit parameter was provided\n T extends {\n queryFn?:\n | QueryFunction\n | SkipTokenForUseQueries\n select?: (data: any) => infer TData\n throwOnError?: ThrowOnError\n }\n ? UseQueryOptionsForUseQueries<\n TQueryFnData,\n unknown extends TError ? DefaultError : TError,\n unknown extends TData ? TQueryFnData : TData,\n TQueryKey\n >\n : // Fallback\n UseQueryOptionsForUseQueries\n\n// A defined initialData setting should return a DefinedUseQueryResult rather than UseQueryResult\ntype GetDefinedOrUndefinedQueryResult = T extends {\n initialData?: infer TInitialData\n}\n ? unknown extends TInitialData\n ? UseQueryResult\n : TInitialData extends TData\n ? DefinedUseQueryResult\n : TInitialData extends () => infer TInitialDataResult\n ? unknown extends TInitialDataResult\n ? UseQueryResult\n : TInitialDataResult extends TData\n ? DefinedUseQueryResult\n : UseQueryResult\n : UseQueryResult\n : UseQueryResult\n\ntype GetUseQueryResult =\n // Part 1: responsible for mapping explicit type parameter to function result, if object\n T extends { queryFnData: any; error?: infer TError; data: infer TData }\n ? GetDefinedOrUndefinedQueryResult\n : T extends { queryFnData: infer TQueryFnData; error?: infer TError }\n ? GetDefinedOrUndefinedQueryResult\n : T extends { data: infer TData; error?: infer TError }\n ? GetDefinedOrUndefinedQueryResult\n : // Part 2: responsible for mapping explicit type parameter to function result, if tuple\n T extends [any, infer TError, infer TData]\n ? GetDefinedOrUndefinedQueryResult\n : T extends [infer TQueryFnData, infer TError]\n ? GetDefinedOrUndefinedQueryResult\n : T extends [infer TQueryFnData]\n ? GetDefinedOrUndefinedQueryResult\n : // Part 3: responsible for mapping inferred type to results, if no explicit parameter was provided\n T extends {\n queryFn?:\n | QueryFunction\n | SkipTokenForUseQueries\n select?: (data: any) => infer TData\n throwOnError?: ThrowOnError\n }\n ? GetDefinedOrUndefinedQueryResult<\n T,\n unknown extends TData ? TQueryFnData : TData,\n unknown extends TError ? DefaultError : TError\n >\n : // Fallback\n UseQueryResult\n\n/**\n * QueriesOptions reducer recursively unwraps function arguments to infer/enforce type param\n */\nexport type QueriesOptions<\n T extends Array,\n TResults extends Array = [],\n TDepth extends ReadonlyArray = [],\n> = TDepth['length'] extends MAXIMUM_DEPTH\n ? Array\n : T extends []\n ? []\n : T extends [infer Head]\n ? [...TResults, GetUseQueryOptionsForUseQueries]\n : T extends [infer Head, ...infer Tails]\n ? QueriesOptions<\n [...Tails],\n [...TResults, GetUseQueryOptionsForUseQueries],\n [...TDepth, 1]\n >\n : ReadonlyArray extends T\n ? T\n : // If T is *some* array but we couldn't assign unknown[] to it, then it must hold some known/homogenous type!\n // use this to infer the param types in the case of Array.map() argument\n T extends Array<\n UseQueryOptionsForUseQueries<\n infer TQueryFnData,\n infer TError,\n infer TData,\n infer TQueryKey\n >\n >\n ? Array<\n UseQueryOptionsForUseQueries<\n TQueryFnData,\n TError,\n TData,\n TQueryKey\n >\n >\n : // Fallback\n Array\n\n/**\n * QueriesResults reducer recursively maps type param to results\n */\nexport type QueriesResults<\n T extends Array,\n TResults extends Array = [],\n TDepth extends ReadonlyArray = [],\n> = TDepth['length'] extends MAXIMUM_DEPTH\n ? Array\n : T extends []\n ? []\n : T extends [infer Head]\n ? [...TResults, GetUseQueryResult]\n : T extends [infer Head, ...infer Tails]\n ? QueriesResults<\n [...Tails],\n [...TResults, GetUseQueryResult],\n [...TDepth, 1]\n >\n : T extends Array<\n UseQueryOptionsForUseQueries<\n infer TQueryFnData,\n infer TError,\n infer TData,\n any\n >\n >\n ? // Dynamic-size (homogenous) UseQueryOptions array: map directly to array of results\n Array<\n UseQueryResult<\n unknown extends TData ? TQueryFnData : TData,\n unknown extends TError ? DefaultError : TError\n >\n >\n : // Fallback\n Array\n\nexport function useQueries<\n T extends Array,\n TCombinedResult = QueriesResults,\n>(\n {\n queries,\n ...options\n }: {\n queries: readonly [...QueriesOptions]\n combine?: (result: QueriesResults) => TCombinedResult\n },\n queryClient?: QueryClient,\n): TCombinedResult {\n const client = useQueryClient(queryClient)\n const isRestoring = useIsRestoring()\n const errorResetBoundary = useQueryErrorResetBoundary()\n\n const defaultedQueries = React.useMemo(\n () =>\n queries.map((opts) => {\n const defaultedOptions = client.defaultQueryOptions(\n opts as QueryObserverOptions,\n )\n\n // Make sure the results are already in fetching state before subscribing or updating options\n defaultedOptions._optimisticResults = isRestoring\n ? 'isRestoring'\n : 'optimistic'\n\n return defaultedOptions\n }),\n [queries, client, isRestoring],\n )\n\n defaultedQueries.forEach((query) => {\n ensureSuspenseTimers(query)\n ensurePreventErrorBoundaryRetry(query, errorResetBoundary)\n })\n\n useClearResetErrorBoundary(errorResetBoundary)\n\n const [observer] = React.useState(\n () =>\n new QueriesObserver(\n client,\n defaultedQueries,\n options as QueriesObserverOptions,\n ),\n )\n\n const [optimisticResult, getCombinedResult, trackResult] =\n observer.getOptimisticResult(\n defaultedQueries,\n (options as QueriesObserverOptions).combine,\n )\n\n useSyncExternalStore(\n React.useCallback(\n (onStoreChange) =>\n isRestoring\n ? noop\n : observer.subscribe(notifyManager.batchCalls(onStoreChange)),\n [observer, isRestoring],\n ),\n () => observer.getCurrentResult(),\n () => observer.getCurrentResult(),\n )\n\n React.useEffect(() => {\n // Do not notify on updates because of changes in the options because\n // these changes should already be reflected in the optimistic result.\n observer.setQueries(\n defaultedQueries,\n options as QueriesObserverOptions,\n {\n listeners: false,\n },\n )\n }, [defaultedQueries, options, observer])\n\n const shouldAtLeastOneSuspend = optimisticResult.some((result, index) =>\n shouldSuspend(defaultedQueries[index], result),\n )\n\n const suspensePromises = shouldAtLeastOneSuspend\n ? optimisticResult.flatMap((result, index) => {\n const opts = defaultedQueries[index]\n\n if (opts) {\n const queryObserver = new QueryObserver(client, opts)\n if (shouldSuspend(opts, result)) {\n return fetchOptimistic(opts, queryObserver, errorResetBoundary)\n } else if (willFetch(result, isRestoring)) {\n void fetchOptimistic(opts, queryObserver, errorResetBoundary)\n }\n }\n return []\n })\n : []\n\n if (suspensePromises.length > 0) {\n throw Promise.all(suspensePromises)\n }\n const firstSingleResultWhichShouldThrow = optimisticResult.find(\n (result, index) => {\n const query = defaultedQueries[index]\n return (\n query &&\n getHasError({\n result,\n errorResetBoundary,\n throwOnError: query.throwOnError,\n query: client.getQueryCache().get(query.queryHash),\n })\n )\n },\n )\n\n if (firstSingleResultWhichShouldThrow?.error) {\n throw firstSingleResultWhichShouldThrow.error\n }\n\n return getCombinedResult(trackResult())\n}\n"],"mappings":";;;AACA,YAAY,WAAW;AACvB,SAAS,4BAA4B;AAErC;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,OACK;AACP,SAAS,sBAAsB;AAC/B,SAAS,sBAAsB;AAC/B,SAAS,kCAAkC;AAC3C;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,OACK;AACP;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OACK;AACP,SAAS,YAAY;AAyMd,SAAS,WAId;AAAA,EACE;AAAA,EACA,GAAG;AACL,GAIA,aACiB;AACjB,QAAM,SAAS,eAAe,WAAW;AACzC,QAAM,cAAc,eAAe;AACnC,QAAM,qBAAqB,2BAA2B;AAEtD,QAAM,mBAAyB;AAAA,IAC7B,MACE,QAAQ,IAAI,CAAC,SAAS;AACpB,YAAM,mBAAmB,OAAO;AAAA,QAC9B;AAAA,MACF;AAGA,uBAAiB,qBAAqB,cAClC,gBACA;AAEJ,aAAO;AAAA,IACT,CAAC;AAAA,IACH,CAAC,SAAS,QAAQ,WAAW;AAAA,EAC/B;AAEA,mBAAiB,QAAQ,CAAC,UAAU;AAClC,yBAAqB,KAAK;AAC1B,oCAAgC,OAAO,kBAAkB;AAAA,EAC3D,CAAC;AAED,6BAA2B,kBAAkB;AAE7C,QAAM,CAAC,QAAQ,IAAU;AAAA,IACvB,MACE,IAAI;AAAA,MACF;AAAA,MACA;AAAA,MACA;AAAA,IACF;AAAA,EACJ;AAEA,QAAM,CAAC,kBAAkB,mBAAmB,WAAW,IACrD,SAAS;AAAA,IACP;AAAA,IACC,QAAoD;AAAA,EACvD;AAEF;AAAA,IACQ;AAAA,MACJ,CAAC,kBACC,cACI,OACA,SAAS,UAAU,cAAc,WAAW,aAAa,CAAC;AAAA,MAChE,CAAC,UAAU,WAAW;AAAA,IACxB;AAAA,IACA,MAAM,SAAS,iBAAiB;AAAA,IAChC,MAAM,SAAS,iBAAiB;AAAA,EAClC;AAEA,EAAM,gBAAU,MAAM;AAGpB,aAAS;AAAA,MACP;AAAA,MACA;AAAA,MACA;AAAA,QACE,WAAW;AAAA,MACb;AAAA,IACF;AAAA,EACF,GAAG,CAAC,kBAAkB,SAAS,QAAQ,CAAC;AAExC,QAAM,0BAA0B,iBAAiB;AAAA,IAAK,CAAC,QAAQ,UAC7D,cAAc,iBAAiB,KAAK,GAAG,MAAM;AAAA,EAC/C;AAEA,QAAM,mBAAmB,0BACrB,iBAAiB,QAAQ,CAAC,QAAQ,UAAU;AAC1C,UAAM,OAAO,iBAAiB,KAAK;AAEnC,QAAI,MAAM;AACR,YAAM,gBAAgB,IAAI,cAAc,QAAQ,IAAI;AACpD,UAAI,cAAc,MAAM,MAAM,GAAG;AAC/B,eAAO,gBAAgB,MAAM,eAAe,kBAAkB;AAAA,MAChE,WAAW,UAAU,QAAQ,WAAW,GAAG;AACzC,aAAK,gBAAgB,MAAM,eAAe,kBAAkB;AAAA,MAC9D;AAAA,IACF;AACA,WAAO,CAAC;AAAA,EACV,CAAC,IACD,CAAC;AAEL,MAAI,iBAAiB,SAAS,GAAG;AAC/B,UAAM,QAAQ,IAAI,gBAAgB;AAAA,EACpC;AACA,QAAM,oCAAoC,iBAAiB;AAAA,IACzD,CAAC,QAAQ,UAAU;AACjB,YAAM,QAAQ,iBAAiB,KAAK;AACpC,aACE,SACA,YAAY;AAAA,QACV;AAAA,QACA;AAAA,QACA,cAAc,MAAM;AAAA,QACpB,OAAO,OAAO,cAAc,EAAE,IAAI,MAAM,SAAS;AAAA,MACnD,CAAC;AAAA,IAEL;AAAA,EACF;AAEA,MAAI,uFAAmC,OAAO;AAC5C,UAAM,kCAAkC;AAAA,EAC1C;AAEA,SAAO,kBAAkB,YAAY,CAAC;AACxC;","names":[]} +\ No newline at end of file +diff --git a/build/modern/useBaseQuery.cjs b/build/modern/useBaseQuery.cjs +index 6b9f949241b8f5dad782c53d96da7a39c22bfeb9..88322155c346a4ce714520ebba0ea954aa128fd0 100644 +--- a/build/modern/useBaseQuery.cjs ++++ b/build/modern/useBaseQuery.cjs +@@ -35,6 +35,7 @@ __export(useBaseQuery_exports, { + }); + module.exports = __toCommonJS(useBaseQuery_exports); + var React = __toESM(require("react"), 1); ++var import_shim = require("use-sync-external-store/shim/index.js"); + var import_query_core = require("@tanstack/query-core"); + var import_QueryClientProvider = require("./QueryClientProvider.cjs"); + var import_QueryErrorResetBoundary = require("./QueryErrorResetBoundary.cjs"); +@@ -69,7 +70,7 @@ function useBaseQuery(options, Observer, queryClient) { + ) + ); + const result = observer.getOptimisticResult(defaultedOptions); +- React.useSyncExternalStore( ++ (0, import_shim.useSyncExternalStore)( + React.useCallback( + (onStoreChange) => { + const unsubscribe = isRestoring ? import_utils.noop : observer.subscribe(import_query_core.notifyManager.batchCalls(onStoreChange)); +diff --git a/build/modern/useBaseQuery.cjs.map b/build/modern/useBaseQuery.cjs.map +index ad9c36de61b6137af70c2432d06d1885250d9c2a..42dc165d1b2aa3f25822a4588f994f461e5ab199 100644 +--- a/build/modern/useBaseQuery.cjs.map ++++ b/build/modern/useBaseQuery.cjs.map +@@ -1 +1 @@ +-{"version":3,"sources":["../../src/useBaseQuery.ts"],"sourcesContent":["'use client'\nimport * as React from 'react'\n\nimport { isServer, notifyManager } from '@tanstack/query-core'\nimport { useQueryClient } from './QueryClientProvider'\nimport { useQueryErrorResetBoundary } from './QueryErrorResetBoundary'\nimport {\n ensurePreventErrorBoundaryRetry,\n getHasError,\n useClearResetErrorBoundary,\n} from './errorBoundaryUtils'\nimport { useIsRestoring } from './isRestoring'\nimport {\n ensureSuspenseTimers,\n fetchOptimistic,\n shouldSuspend,\n willFetch,\n} from './suspense'\nimport { noop } from './utils'\nimport type {\n QueryClient,\n QueryKey,\n QueryObserver,\n QueryObserverResult,\n} from '@tanstack/query-core'\nimport type { UseBaseQueryOptions } from './types'\n\nexport function useBaseQuery<\n TQueryFnData,\n TError,\n TData,\n TQueryData,\n TQueryKey extends QueryKey,\n>(\n options: UseBaseQueryOptions<\n TQueryFnData,\n TError,\n TData,\n TQueryData,\n TQueryKey\n >,\n Observer: typeof QueryObserver,\n queryClient?: QueryClient,\n): QueryObserverResult {\n if (process.env.NODE_ENV !== 'production') {\n if (typeof options !== 'object' || Array.isArray(options)) {\n throw new Error(\n 'Bad argument type. Starting with v5, only the \"Object\" form is allowed when calling query related functions. Please use the error stack to find the culprit call. More info here: https://tanstack.com/query/latest/docs/react/guides/migrating-to-v5#supports-a-single-signature-one-object',\n )\n }\n }\n\n const client = useQueryClient(queryClient)\n const isRestoring = useIsRestoring()\n const errorResetBoundary = useQueryErrorResetBoundary()\n const defaultedOptions = client.defaultQueryOptions(options)\n\n ;(client.getDefaultOptions().queries as any)?._experimental_beforeQuery?.(\n defaultedOptions,\n )\n\n // Make sure results are optimistically set in fetching state before subscribing or updating options\n defaultedOptions._optimisticResults = isRestoring\n ? 'isRestoring'\n : 'optimistic'\n\n ensureSuspenseTimers(defaultedOptions)\n ensurePreventErrorBoundaryRetry(defaultedOptions, errorResetBoundary)\n\n useClearResetErrorBoundary(errorResetBoundary)\n\n // this needs to be invoked before creating the Observer because that can create a cache entry\n const isNewCacheEntry = !client\n .getQueryCache()\n .get(defaultedOptions.queryHash)\n\n const [observer] = React.useState(\n () =>\n new Observer(\n client,\n defaultedOptions,\n ),\n )\n\n const result = observer.getOptimisticResult(defaultedOptions)\n\n React.useSyncExternalStore(\n React.useCallback(\n (onStoreChange) => {\n const unsubscribe = isRestoring\n ? noop\n : observer.subscribe(notifyManager.batchCalls(onStoreChange))\n\n // Update result to make sure we did not miss any query updates\n // between creating the observer and subscribing to it.\n observer.updateResult()\n\n return unsubscribe\n },\n [observer, isRestoring],\n ),\n () => observer.getCurrentResult(),\n () => observer.getCurrentResult(),\n )\n\n React.useEffect(() => {\n // Do not notify on updates because of changes in the options because\n // these changes should already be reflected in the optimistic result.\n observer.setOptions(defaultedOptions, { listeners: false })\n }, [defaultedOptions, observer])\n\n // Handle suspense\n if (shouldSuspend(defaultedOptions, result)) {\n throw fetchOptimistic(defaultedOptions, observer, errorResetBoundary)\n }\n\n // Handle error boundary\n if (\n getHasError({\n result,\n errorResetBoundary,\n throwOnError: defaultedOptions.throwOnError,\n query: client\n .getQueryCache()\n .get<\n TQueryFnData,\n TError,\n TQueryData,\n TQueryKey\n >(defaultedOptions.queryHash),\n })\n ) {\n throw result.error\n }\n\n ;(client.getDefaultOptions().queries as any)?._experimental_afterQuery?.(\n defaultedOptions,\n result,\n )\n\n if (\n defaultedOptions.experimental_prefetchInRender &&\n !isServer &&\n willFetch(result, isRestoring)\n ) {\n const promise = isNewCacheEntry\n ? // Fetch immediately on render in order to ensure `.promise` is resolved even if the component is unmounted\n fetchOptimistic(defaultedOptions, observer, errorResetBoundary)\n : // subscribe to the \"cache promise\" so that we can finalize the currentThenable once data comes in\n client.getQueryCache().get(defaultedOptions.queryHash)?.promise\n\n promise?.catch(noop).finally(() => {\n // `.updateResult()` will trigger `.#currentThenable` to finalize\n observer.updateResult()\n })\n }\n\n // Handle result property usage tracking\n return !defaultedOptions.notifyOnChangeProps\n ? observer.trackResult(result)\n : result\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AACA,YAAuB;AAEvB,wBAAwC;AACxC,iCAA+B;AAC/B,qCAA2C;AAC3C,gCAIO;AACP,yBAA+B;AAC/B,sBAKO;AACP,mBAAqB;AASd,SAAS,aAOd,SAOA,UACA,aACoC;AACpC,MAAI,QAAQ,IAAI,aAAa,cAAc;AACzC,QAAI,OAAO,YAAY,YAAY,MAAM,QAAQ,OAAO,GAAG;AACzD,YAAM,IAAI;AAAA,QACR;AAAA,MACF;AAAA,IACF;AAAA,EACF;AAEA,QAAM,aAAS,2CAAe,WAAW;AACzC,QAAM,kBAAc,mCAAe;AACnC,QAAM,yBAAqB,2DAA2B;AACtD,QAAM,mBAAmB,OAAO,oBAAoB,OAAO;AAE1D,EAAC,OAAO,kBAAkB,EAAE,SAAiB;AAAA,IAC5C;AAAA,EACF;AAGA,mBAAiB,qBAAqB,cAClC,gBACA;AAEJ,4CAAqB,gBAAgB;AACrC,iEAAgC,kBAAkB,kBAAkB;AAEpE,4DAA2B,kBAAkB;AAG7C,QAAM,kBAAkB,CAAC,OACtB,cAAc,EACd,IAAI,iBAAiB,SAAS;AAEjC,QAAM,CAAC,QAAQ,IAAU;AAAA,IACvB,MACE,IAAI;AAAA,MACF;AAAA,MACA;AAAA,IACF;AAAA,EACJ;AAEA,QAAM,SAAS,SAAS,oBAAoB,gBAAgB;AAE5D,EAAM;AAAA,IACE;AAAA,MACJ,CAAC,kBAAkB;AACjB,cAAM,cAAc,cAChB,oBACA,SAAS,UAAU,gCAAc,WAAW,aAAa,CAAC;AAI9D,iBAAS,aAAa;AAEtB,eAAO;AAAA,MACT;AAAA,MACA,CAAC,UAAU,WAAW;AAAA,IACxB;AAAA,IACA,MAAM,SAAS,iBAAiB;AAAA,IAChC,MAAM,SAAS,iBAAiB;AAAA,EAClC;AAEA,EAAM,gBAAU,MAAM;AAGpB,aAAS,WAAW,kBAAkB,EAAE,WAAW,MAAM,CAAC;AAAA,EAC5D,GAAG,CAAC,kBAAkB,QAAQ,CAAC;AAG/B,UAAI,+BAAc,kBAAkB,MAAM,GAAG;AAC3C,cAAM,iCAAgB,kBAAkB,UAAU,kBAAkB;AAAA,EACtE;AAGA,UACE,uCAAY;AAAA,IACV;AAAA,IACA;AAAA,IACA,cAAc,iBAAiB;AAAA,IAC/B,OAAO,OACJ,cAAc,EACd,IAKC,iBAAiB,SAAS;AAAA,EAChC,CAAC,GACD;AACA,UAAM,OAAO;AAAA,EACf;AAEA;AAAC,EAAC,OAAO,kBAAkB,EAAE,SAAiB;AAAA,IAC5C;AAAA,IACA;AAAA,EACF;AAEA,MACE,iBAAiB,iCACjB,CAAC,kCACD,2BAAU,QAAQ,WAAW,GAC7B;AACA,UAAM,UAAU;AAAA;AAAA,UAEZ,iCAAgB,kBAAkB,UAAU,kBAAkB;AAAA;AAAA;AAAA,MAE9D,OAAO,cAAc,EAAE,IAAI,iBAAiB,SAAS,GAAG;AAAA;AAE5D,aAAS,MAAM,iBAAI,EAAE,QAAQ,MAAM;AAEjC,eAAS,aAAa;AAAA,IACxB,CAAC;AAAA,EACH;AAGA,SAAO,CAAC,iBAAiB,sBACrB,SAAS,YAAY,MAAM,IAC3B;AACN;","names":[]} +\ No newline at end of file ++{"version":3,"sources":["../../src/useBaseQuery.ts"],"sourcesContent":["'use client'\nimport * as React from 'react'\nimport { useSyncExternalStore } from 'use-sync-external-store/shim/index.js'\n\nimport { isServer, notifyManager } from '@tanstack/query-core'\nimport { useQueryClient } from './QueryClientProvider'\nimport { useQueryErrorResetBoundary } from './QueryErrorResetBoundary'\nimport {\n ensurePreventErrorBoundaryRetry,\n getHasError,\n useClearResetErrorBoundary,\n} from './errorBoundaryUtils'\nimport { useIsRestoring } from './isRestoring'\nimport {\n ensureSuspenseTimers,\n fetchOptimistic,\n shouldSuspend,\n willFetch,\n} from './suspense'\nimport { noop } from './utils'\nimport type {\n QueryClient,\n QueryKey,\n QueryObserver,\n QueryObserverResult,\n} from '@tanstack/query-core'\nimport type { UseBaseQueryOptions } from './types'\n\nexport function useBaseQuery<\n TQueryFnData,\n TError,\n TData,\n TQueryData,\n TQueryKey extends QueryKey,\n>(\n options: UseBaseQueryOptions<\n TQueryFnData,\n TError,\n TData,\n TQueryData,\n TQueryKey\n >,\n Observer: typeof QueryObserver,\n queryClient?: QueryClient,\n): QueryObserverResult {\n if (process.env.NODE_ENV !== 'production') {\n if (typeof options !== 'object' || Array.isArray(options)) {\n throw new Error(\n 'Bad argument type. Starting with v5, only the \"Object\" form is allowed when calling query related functions. Please use the error stack to find the culprit call. More info here: https://tanstack.com/query/latest/docs/react/guides/migrating-to-v5#supports-a-single-signature-one-object',\n )\n }\n }\n\n const client = useQueryClient(queryClient)\n const isRestoring = useIsRestoring()\n const errorResetBoundary = useQueryErrorResetBoundary()\n const defaultedOptions = client.defaultQueryOptions(options)\n\n ;(client.getDefaultOptions().queries as any)?._experimental_beforeQuery?.(\n defaultedOptions,\n )\n\n // Make sure results are optimistically set in fetching state before subscribing or updating options\n defaultedOptions._optimisticResults = isRestoring\n ? 'isRestoring'\n : 'optimistic'\n\n ensureSuspenseTimers(defaultedOptions)\n ensurePreventErrorBoundaryRetry(defaultedOptions, errorResetBoundary)\n\n useClearResetErrorBoundary(errorResetBoundary)\n\n // this needs to be invoked before creating the Observer because that can create a cache entry\n const isNewCacheEntry = !client\n .getQueryCache()\n .get(defaultedOptions.queryHash)\n\n const [observer] = React.useState(\n () =>\n new Observer(\n client,\n defaultedOptions,\n ),\n )\n\n const result = observer.getOptimisticResult(defaultedOptions)\n\n useSyncExternalStore(\n React.useCallback(\n (onStoreChange) => {\n const unsubscribe = isRestoring\n ? noop\n : observer.subscribe(notifyManager.batchCalls(onStoreChange))\n\n // Update result to make sure we did not miss any query updates\n // between creating the observer and subscribing to it.\n observer.updateResult()\n\n return unsubscribe\n },\n [observer, isRestoring],\n ),\n () => observer.getCurrentResult(),\n () => observer.getCurrentResult(),\n )\n\n React.useEffect(() => {\n // Do not notify on updates because of changes in the options because\n // these changes should already be reflected in the optimistic result.\n observer.setOptions(defaultedOptions, { listeners: false })\n }, [defaultedOptions, observer])\n\n // Handle suspense\n if (shouldSuspend(defaultedOptions, result)) {\n throw fetchOptimistic(defaultedOptions, observer, errorResetBoundary)\n }\n\n // Handle error boundary\n if (\n getHasError({\n result,\n errorResetBoundary,\n throwOnError: defaultedOptions.throwOnError,\n query: client\n .getQueryCache()\n .get<\n TQueryFnData,\n TError,\n TQueryData,\n TQueryKey\n >(defaultedOptions.queryHash),\n })\n ) {\n throw result.error\n }\n\n ;(client.getDefaultOptions().queries as any)?._experimental_afterQuery?.(\n defaultedOptions,\n result,\n )\n\n if (\n defaultedOptions.experimental_prefetchInRender &&\n !isServer &&\n willFetch(result, isRestoring)\n ) {\n const promise = isNewCacheEntry\n ? // Fetch immediately on render in order to ensure `.promise` is resolved even if the component is unmounted\n fetchOptimistic(defaultedOptions, observer, errorResetBoundary)\n : // subscribe to the \"cache promise\" so that we can finalize the currentThenable once data comes in\n client.getQueryCache().get(defaultedOptions.queryHash)?.promise\n\n promise?.catch(noop).finally(() => {\n // `.updateResult()` will trigger `.#currentThenable` to finalize\n observer.updateResult()\n })\n }\n\n // Handle result property usage tracking\n return !defaultedOptions.notifyOnChangeProps\n ? observer.trackResult(result)\n : result\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AACA,YAAuB;AACvB,kBAAqC;AAErC,wBAAwC;AACxC,iCAA+B;AAC/B,qCAA2C;AAC3C,gCAIO;AACP,yBAA+B;AAC/B,sBAKO;AACP,mBAAqB;AASd,SAAS,aAOd,SAOA,UACA,aACoC;AACpC,MAAI,QAAQ,IAAI,aAAa,cAAc;AACzC,QAAI,OAAO,YAAY,YAAY,MAAM,QAAQ,OAAO,GAAG;AACzD,YAAM,IAAI;AAAA,QACR;AAAA,MACF;AAAA,IACF;AAAA,EACF;AAEA,QAAM,aAAS,2CAAe,WAAW;AACzC,QAAM,kBAAc,mCAAe;AACnC,QAAM,yBAAqB,2DAA2B;AACtD,QAAM,mBAAmB,OAAO,oBAAoB,OAAO;AAE1D,EAAC,OAAO,kBAAkB,EAAE,SAAiB;AAAA,IAC5C;AAAA,EACF;AAGA,mBAAiB,qBAAqB,cAClC,gBACA;AAEJ,4CAAqB,gBAAgB;AACrC,iEAAgC,kBAAkB,kBAAkB;AAEpE,4DAA2B,kBAAkB;AAG7C,QAAM,kBAAkB,CAAC,OACtB,cAAc,EACd,IAAI,iBAAiB,SAAS;AAEjC,QAAM,CAAC,QAAQ,IAAU;AAAA,IACvB,MACE,IAAI;AAAA,MACF;AAAA,MACA;AAAA,IACF;AAAA,EACJ;AAEA,QAAM,SAAS,SAAS,oBAAoB,gBAAgB;AAE5D;AAAA,IACQ;AAAA,MACJ,CAAC,kBAAkB;AACjB,cAAM,cAAc,cAChB,oBACA,SAAS,UAAU,gCAAc,WAAW,aAAa,CAAC;AAI9D,iBAAS,aAAa;AAEtB,eAAO;AAAA,MACT;AAAA,MACA,CAAC,UAAU,WAAW;AAAA,IACxB;AAAA,IACA,MAAM,SAAS,iBAAiB;AAAA,IAChC,MAAM,SAAS,iBAAiB;AAAA,EAClC;AAEA,EAAM,gBAAU,MAAM;AAGpB,aAAS,WAAW,kBAAkB,EAAE,WAAW,MAAM,CAAC;AAAA,EAC5D,GAAG,CAAC,kBAAkB,QAAQ,CAAC;AAG/B,UAAI,+BAAc,kBAAkB,MAAM,GAAG;AAC3C,cAAM,iCAAgB,kBAAkB,UAAU,kBAAkB;AAAA,EACtE;AAGA,UACE,uCAAY;AAAA,IACV;AAAA,IACA;AAAA,IACA,cAAc,iBAAiB;AAAA,IAC/B,OAAO,OACJ,cAAc,EACd,IAKC,iBAAiB,SAAS;AAAA,EAChC,CAAC,GACD;AACA,UAAM,OAAO;AAAA,EACf;AAEA;AAAC,EAAC,OAAO,kBAAkB,EAAE,SAAiB;AAAA,IAC5C;AAAA,IACA;AAAA,EACF;AAEA,MACE,iBAAiB,iCACjB,CAAC,kCACD,2BAAU,QAAQ,WAAW,GAC7B;AACA,UAAM,UAAU;AAAA;AAAA,UAEZ,iCAAgB,kBAAkB,UAAU,kBAAkB;AAAA;AAAA;AAAA,MAE9D,OAAO,cAAc,EAAE,IAAI,iBAAiB,SAAS,GAAG;AAAA;AAE5D,aAAS,MAAM,iBAAI,EAAE,QAAQ,MAAM;AAEjC,eAAS,aAAa;AAAA,IACxB,CAAC;AAAA,EACH;AAGA,SAAO,CAAC,iBAAiB,sBACrB,SAAS,YAAY,MAAM,IAC3B;AACN;","names":[]} +\ No newline at end of file +diff --git a/build/modern/useBaseQuery.js b/build/modern/useBaseQuery.js +index e8cf3a4fba4c6f8ddbbdf8ebd3fdad054a059d0c..9758bc05f3f2b76c980a7b52276c95e7db1a8ac8 100644 +--- a/build/modern/useBaseQuery.js ++++ b/build/modern/useBaseQuery.js +@@ -2,6 +2,7 @@ + + // src/useBaseQuery.ts + import * as React from "react"; ++import { useSyncExternalStore } from "use-sync-external-store/shim/index.js"; + import { isServer, notifyManager } from "@tanstack/query-core"; + import { useQueryClient } from "./QueryClientProvider.js"; + import { useQueryErrorResetBoundary } from "./QueryErrorResetBoundary.js"; +@@ -45,7 +46,7 @@ function useBaseQuery(options, Observer, queryClient) { + ) + ); + const result = observer.getOptimisticResult(defaultedOptions); +- React.useSyncExternalStore( ++ useSyncExternalStore( + React.useCallback( + (onStoreChange) => { + const unsubscribe = isRestoring ? noop : observer.subscribe(notifyManager.batchCalls(onStoreChange)); +diff --git a/build/modern/useBaseQuery.js.map b/build/modern/useBaseQuery.js.map +index b84572b8d8230d96a606652f24faf97f3ff366e4..13bb6e0982b96216f9c90d97a69a2ac3adb6274b 100644 +--- a/build/modern/useBaseQuery.js.map ++++ b/build/modern/useBaseQuery.js.map +@@ -1 +1 @@ +-{"version":3,"sources":["../../src/useBaseQuery.ts"],"sourcesContent":["'use client'\nimport * as React from 'react'\n\nimport { isServer, notifyManager } from '@tanstack/query-core'\nimport { useQueryClient } from './QueryClientProvider'\nimport { useQueryErrorResetBoundary } from './QueryErrorResetBoundary'\nimport {\n ensurePreventErrorBoundaryRetry,\n getHasError,\n useClearResetErrorBoundary,\n} from './errorBoundaryUtils'\nimport { useIsRestoring } from './isRestoring'\nimport {\n ensureSuspenseTimers,\n fetchOptimistic,\n shouldSuspend,\n willFetch,\n} from './suspense'\nimport { noop } from './utils'\nimport type {\n QueryClient,\n QueryKey,\n QueryObserver,\n QueryObserverResult,\n} from '@tanstack/query-core'\nimport type { UseBaseQueryOptions } from './types'\n\nexport function useBaseQuery<\n TQueryFnData,\n TError,\n TData,\n TQueryData,\n TQueryKey extends QueryKey,\n>(\n options: UseBaseQueryOptions<\n TQueryFnData,\n TError,\n TData,\n TQueryData,\n TQueryKey\n >,\n Observer: typeof QueryObserver,\n queryClient?: QueryClient,\n): QueryObserverResult {\n if (process.env.NODE_ENV !== 'production') {\n if (typeof options !== 'object' || Array.isArray(options)) {\n throw new Error(\n 'Bad argument type. Starting with v5, only the \"Object\" form is allowed when calling query related functions. Please use the error stack to find the culprit call. More info here: https://tanstack.com/query/latest/docs/react/guides/migrating-to-v5#supports-a-single-signature-one-object',\n )\n }\n }\n\n const client = useQueryClient(queryClient)\n const isRestoring = useIsRestoring()\n const errorResetBoundary = useQueryErrorResetBoundary()\n const defaultedOptions = client.defaultQueryOptions(options)\n\n ;(client.getDefaultOptions().queries as any)?._experimental_beforeQuery?.(\n defaultedOptions,\n )\n\n // Make sure results are optimistically set in fetching state before subscribing or updating options\n defaultedOptions._optimisticResults = isRestoring\n ? 'isRestoring'\n : 'optimistic'\n\n ensureSuspenseTimers(defaultedOptions)\n ensurePreventErrorBoundaryRetry(defaultedOptions, errorResetBoundary)\n\n useClearResetErrorBoundary(errorResetBoundary)\n\n // this needs to be invoked before creating the Observer because that can create a cache entry\n const isNewCacheEntry = !client\n .getQueryCache()\n .get(defaultedOptions.queryHash)\n\n const [observer] = React.useState(\n () =>\n new Observer(\n client,\n defaultedOptions,\n ),\n )\n\n const result = observer.getOptimisticResult(defaultedOptions)\n\n React.useSyncExternalStore(\n React.useCallback(\n (onStoreChange) => {\n const unsubscribe = isRestoring\n ? noop\n : observer.subscribe(notifyManager.batchCalls(onStoreChange))\n\n // Update result to make sure we did not miss any query updates\n // between creating the observer and subscribing to it.\n observer.updateResult()\n\n return unsubscribe\n },\n [observer, isRestoring],\n ),\n () => observer.getCurrentResult(),\n () => observer.getCurrentResult(),\n )\n\n React.useEffect(() => {\n // Do not notify on updates because of changes in the options because\n // these changes should already be reflected in the optimistic result.\n observer.setOptions(defaultedOptions, { listeners: false })\n }, [defaultedOptions, observer])\n\n // Handle suspense\n if (shouldSuspend(defaultedOptions, result)) {\n throw fetchOptimistic(defaultedOptions, observer, errorResetBoundary)\n }\n\n // Handle error boundary\n if (\n getHasError({\n result,\n errorResetBoundary,\n throwOnError: defaultedOptions.throwOnError,\n query: client\n .getQueryCache()\n .get<\n TQueryFnData,\n TError,\n TQueryData,\n TQueryKey\n >(defaultedOptions.queryHash),\n })\n ) {\n throw result.error\n }\n\n ;(client.getDefaultOptions().queries as any)?._experimental_afterQuery?.(\n defaultedOptions,\n result,\n )\n\n if (\n defaultedOptions.experimental_prefetchInRender &&\n !isServer &&\n willFetch(result, isRestoring)\n ) {\n const promise = isNewCacheEntry\n ? // Fetch immediately on render in order to ensure `.promise` is resolved even if the component is unmounted\n fetchOptimistic(defaultedOptions, observer, errorResetBoundary)\n : // subscribe to the \"cache promise\" so that we can finalize the currentThenable once data comes in\n client.getQueryCache().get(defaultedOptions.queryHash)?.promise\n\n promise?.catch(noop).finally(() => {\n // `.updateResult()` will trigger `.#currentThenable` to finalize\n observer.updateResult()\n })\n }\n\n // Handle result property usage tracking\n return !defaultedOptions.notifyOnChangeProps\n ? observer.trackResult(result)\n : result\n}\n"],"mappings":";;;AACA,YAAY,WAAW;AAEvB,SAAS,UAAU,qBAAqB;AACxC,SAAS,sBAAsB;AAC/B,SAAS,kCAAkC;AAC3C;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,OACK;AACP,SAAS,sBAAsB;AAC/B;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OACK;AACP,SAAS,YAAY;AASd,SAAS,aAOd,SAOA,UACA,aACoC;AACpC,MAAI,QAAQ,IAAI,aAAa,cAAc;AACzC,QAAI,OAAO,YAAY,YAAY,MAAM,QAAQ,OAAO,GAAG;AACzD,YAAM,IAAI;AAAA,QACR;AAAA,MACF;AAAA,IACF;AAAA,EACF;AAEA,QAAM,SAAS,eAAe,WAAW;AACzC,QAAM,cAAc,eAAe;AACnC,QAAM,qBAAqB,2BAA2B;AACtD,QAAM,mBAAmB,OAAO,oBAAoB,OAAO;AAE1D,EAAC,OAAO,kBAAkB,EAAE,SAAiB;AAAA,IAC5C;AAAA,EACF;AAGA,mBAAiB,qBAAqB,cAClC,gBACA;AAEJ,uBAAqB,gBAAgB;AACrC,kCAAgC,kBAAkB,kBAAkB;AAEpE,6BAA2B,kBAAkB;AAG7C,QAAM,kBAAkB,CAAC,OACtB,cAAc,EACd,IAAI,iBAAiB,SAAS;AAEjC,QAAM,CAAC,QAAQ,IAAU;AAAA,IACvB,MACE,IAAI;AAAA,MACF;AAAA,MACA;AAAA,IACF;AAAA,EACJ;AAEA,QAAM,SAAS,SAAS,oBAAoB,gBAAgB;AAE5D,EAAM;AAAA,IACE;AAAA,MACJ,CAAC,kBAAkB;AACjB,cAAM,cAAc,cAChB,OACA,SAAS,UAAU,cAAc,WAAW,aAAa,CAAC;AAI9D,iBAAS,aAAa;AAEtB,eAAO;AAAA,MACT;AAAA,MACA,CAAC,UAAU,WAAW;AAAA,IACxB;AAAA,IACA,MAAM,SAAS,iBAAiB;AAAA,IAChC,MAAM,SAAS,iBAAiB;AAAA,EAClC;AAEA,EAAM,gBAAU,MAAM;AAGpB,aAAS,WAAW,kBAAkB,EAAE,WAAW,MAAM,CAAC;AAAA,EAC5D,GAAG,CAAC,kBAAkB,QAAQ,CAAC;AAG/B,MAAI,cAAc,kBAAkB,MAAM,GAAG;AAC3C,UAAM,gBAAgB,kBAAkB,UAAU,kBAAkB;AAAA,EACtE;AAGA,MACE,YAAY;AAAA,IACV;AAAA,IACA;AAAA,IACA,cAAc,iBAAiB;AAAA,IAC/B,OAAO,OACJ,cAAc,EACd,IAKC,iBAAiB,SAAS;AAAA,EAChC,CAAC,GACD;AACA,UAAM,OAAO;AAAA,EACf;AAEA;AAAC,EAAC,OAAO,kBAAkB,EAAE,SAAiB;AAAA,IAC5C;AAAA,IACA;AAAA,EACF;AAEA,MACE,iBAAiB,iCACjB,CAAC,YACD,UAAU,QAAQ,WAAW,GAC7B;AACA,UAAM,UAAU;AAAA;AAAA,MAEZ,gBAAgB,kBAAkB,UAAU,kBAAkB;AAAA;AAAA;AAAA,MAE9D,OAAO,cAAc,EAAE,IAAI,iBAAiB,SAAS,GAAG;AAAA;AAE5D,aAAS,MAAM,IAAI,EAAE,QAAQ,MAAM;AAEjC,eAAS,aAAa;AAAA,IACxB,CAAC;AAAA,EACH;AAGA,SAAO,CAAC,iBAAiB,sBACrB,SAAS,YAAY,MAAM,IAC3B;AACN;","names":[]} +\ No newline at end of file ++{"version":3,"sources":["../../src/useBaseQuery.ts"],"sourcesContent":["'use client'\nimport * as React from 'react'\nimport { useSyncExternalStore } from 'use-sync-external-store/shim/index.js'\n\nimport { isServer, notifyManager } from '@tanstack/query-core'\nimport { useQueryClient } from './QueryClientProvider'\nimport { useQueryErrorResetBoundary } from './QueryErrorResetBoundary'\nimport {\n ensurePreventErrorBoundaryRetry,\n getHasError,\n useClearResetErrorBoundary,\n} from './errorBoundaryUtils'\nimport { useIsRestoring } from './isRestoring'\nimport {\n ensureSuspenseTimers,\n fetchOptimistic,\n shouldSuspend,\n willFetch,\n} from './suspense'\nimport { noop } from './utils'\nimport type {\n QueryClient,\n QueryKey,\n QueryObserver,\n QueryObserverResult,\n} from '@tanstack/query-core'\nimport type { UseBaseQueryOptions } from './types'\n\nexport function useBaseQuery<\n TQueryFnData,\n TError,\n TData,\n TQueryData,\n TQueryKey extends QueryKey,\n>(\n options: UseBaseQueryOptions<\n TQueryFnData,\n TError,\n TData,\n TQueryData,\n TQueryKey\n >,\n Observer: typeof QueryObserver,\n queryClient?: QueryClient,\n): QueryObserverResult {\n if (process.env.NODE_ENV !== 'production') {\n if (typeof options !== 'object' || Array.isArray(options)) {\n throw new Error(\n 'Bad argument type. Starting with v5, only the \"Object\" form is allowed when calling query related functions. Please use the error stack to find the culprit call. More info here: https://tanstack.com/query/latest/docs/react/guides/migrating-to-v5#supports-a-single-signature-one-object',\n )\n }\n }\n\n const client = useQueryClient(queryClient)\n const isRestoring = useIsRestoring()\n const errorResetBoundary = useQueryErrorResetBoundary()\n const defaultedOptions = client.defaultQueryOptions(options)\n\n ;(client.getDefaultOptions().queries as any)?._experimental_beforeQuery?.(\n defaultedOptions,\n )\n\n // Make sure results are optimistically set in fetching state before subscribing or updating options\n defaultedOptions._optimisticResults = isRestoring\n ? 'isRestoring'\n : 'optimistic'\n\n ensureSuspenseTimers(defaultedOptions)\n ensurePreventErrorBoundaryRetry(defaultedOptions, errorResetBoundary)\n\n useClearResetErrorBoundary(errorResetBoundary)\n\n // this needs to be invoked before creating the Observer because that can create a cache entry\n const isNewCacheEntry = !client\n .getQueryCache()\n .get(defaultedOptions.queryHash)\n\n const [observer] = React.useState(\n () =>\n new Observer(\n client,\n defaultedOptions,\n ),\n )\n\n const result = observer.getOptimisticResult(defaultedOptions)\n\n useSyncExternalStore(\n React.useCallback(\n (onStoreChange) => {\n const unsubscribe = isRestoring\n ? noop\n : observer.subscribe(notifyManager.batchCalls(onStoreChange))\n\n // Update result to make sure we did not miss any query updates\n // between creating the observer and subscribing to it.\n observer.updateResult()\n\n return unsubscribe\n },\n [observer, isRestoring],\n ),\n () => observer.getCurrentResult(),\n () => observer.getCurrentResult(),\n )\n\n React.useEffect(() => {\n // Do not notify on updates because of changes in the options because\n // these changes should already be reflected in the optimistic result.\n observer.setOptions(defaultedOptions, { listeners: false })\n }, [defaultedOptions, observer])\n\n // Handle suspense\n if (shouldSuspend(defaultedOptions, result)) {\n throw fetchOptimistic(defaultedOptions, observer, errorResetBoundary)\n }\n\n // Handle error boundary\n if (\n getHasError({\n result,\n errorResetBoundary,\n throwOnError: defaultedOptions.throwOnError,\n query: client\n .getQueryCache()\n .get<\n TQueryFnData,\n TError,\n TQueryData,\n TQueryKey\n >(defaultedOptions.queryHash),\n })\n ) {\n throw result.error\n }\n\n ;(client.getDefaultOptions().queries as any)?._experimental_afterQuery?.(\n defaultedOptions,\n result,\n )\n\n if (\n defaultedOptions.experimental_prefetchInRender &&\n !isServer &&\n willFetch(result, isRestoring)\n ) {\n const promise = isNewCacheEntry\n ? // Fetch immediately on render in order to ensure `.promise` is resolved even if the component is unmounted\n fetchOptimistic(defaultedOptions, observer, errorResetBoundary)\n : // subscribe to the \"cache promise\" so that we can finalize the currentThenable once data comes in\n client.getQueryCache().get(defaultedOptions.queryHash)?.promise\n\n promise?.catch(noop).finally(() => {\n // `.updateResult()` will trigger `.#currentThenable` to finalize\n observer.updateResult()\n })\n }\n\n // Handle result property usage tracking\n return !defaultedOptions.notifyOnChangeProps\n ? observer.trackResult(result)\n : result\n}\n"],"mappings":";;;AACA,YAAY,WAAW;AACvB,SAAS,4BAA4B;AAErC,SAAS,UAAU,qBAAqB;AACxC,SAAS,sBAAsB;AAC/B,SAAS,kCAAkC;AAC3C;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,OACK;AACP,SAAS,sBAAsB;AAC/B;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OACK;AACP,SAAS,YAAY;AASd,SAAS,aAOd,SAOA,UACA,aACoC;AACpC,MAAI,QAAQ,IAAI,aAAa,cAAc;AACzC,QAAI,OAAO,YAAY,YAAY,MAAM,QAAQ,OAAO,GAAG;AACzD,YAAM,IAAI;AAAA,QACR;AAAA,MACF;AAAA,IACF;AAAA,EACF;AAEA,QAAM,SAAS,eAAe,WAAW;AACzC,QAAM,cAAc,eAAe;AACnC,QAAM,qBAAqB,2BAA2B;AACtD,QAAM,mBAAmB,OAAO,oBAAoB,OAAO;AAE1D,EAAC,OAAO,kBAAkB,EAAE,SAAiB;AAAA,IAC5C;AAAA,EACF;AAGA,mBAAiB,qBAAqB,cAClC,gBACA;AAEJ,uBAAqB,gBAAgB;AACrC,kCAAgC,kBAAkB,kBAAkB;AAEpE,6BAA2B,kBAAkB;AAG7C,QAAM,kBAAkB,CAAC,OACtB,cAAc,EACd,IAAI,iBAAiB,SAAS;AAEjC,QAAM,CAAC,QAAQ,IAAU;AAAA,IACvB,MACE,IAAI;AAAA,MACF;AAAA,MACA;AAAA,IACF;AAAA,EACJ;AAEA,QAAM,SAAS,SAAS,oBAAoB,gBAAgB;AAE5D;AAAA,IACQ;AAAA,MACJ,CAAC,kBAAkB;AACjB,cAAM,cAAc,cAChB,OACA,SAAS,UAAU,cAAc,WAAW,aAAa,CAAC;AAI9D,iBAAS,aAAa;AAEtB,eAAO;AAAA,MACT;AAAA,MACA,CAAC,UAAU,WAAW;AAAA,IACxB;AAAA,IACA,MAAM,SAAS,iBAAiB;AAAA,IAChC,MAAM,SAAS,iBAAiB;AAAA,EAClC;AAEA,EAAM,gBAAU,MAAM;AAGpB,aAAS,WAAW,kBAAkB,EAAE,WAAW,MAAM,CAAC;AAAA,EAC5D,GAAG,CAAC,kBAAkB,QAAQ,CAAC;AAG/B,MAAI,cAAc,kBAAkB,MAAM,GAAG;AAC3C,UAAM,gBAAgB,kBAAkB,UAAU,kBAAkB;AAAA,EACtE;AAGA,MACE,YAAY;AAAA,IACV;AAAA,IACA;AAAA,IACA,cAAc,iBAAiB;AAAA,IAC/B,OAAO,OACJ,cAAc,EACd,IAKC,iBAAiB,SAAS;AAAA,EAChC,CAAC,GACD;AACA,UAAM,OAAO;AAAA,EACf;AAEA;AAAC,EAAC,OAAO,kBAAkB,EAAE,SAAiB;AAAA,IAC5C;AAAA,IACA;AAAA,EACF;AAEA,MACE,iBAAiB,iCACjB,CAAC,YACD,UAAU,QAAQ,WAAW,GAC7B;AACA,UAAM,UAAU;AAAA;AAAA,MAEZ,gBAAgB,kBAAkB,UAAU,kBAAkB;AAAA;AAAA;AAAA,MAE9D,OAAO,cAAc,EAAE,IAAI,iBAAiB,SAAS,GAAG;AAAA;AAE5D,aAAS,MAAM,IAAI,EAAE,QAAQ,MAAM;AAEjC,eAAS,aAAa;AAAA,IACxB,CAAC;AAAA,EACH;AAGA,SAAO,CAAC,iBAAiB,sBACrB,SAAS,YAAY,MAAM,IAC3B;AACN;","names":[]} +\ No newline at end of file +diff --git a/build/modern/useIsFetching.cjs b/build/modern/useIsFetching.cjs +index 28660e7d19489acc86f6a2f0c9b47e453ac66fae..2bed8ddef2f97adfb60c35aa83630259898e5e20 100644 +--- a/build/modern/useIsFetching.cjs ++++ b/build/modern/useIsFetching.cjs +@@ -35,12 +35,13 @@ __export(useIsFetching_exports, { + }); + module.exports = __toCommonJS(useIsFetching_exports); + var React = __toESM(require("react"), 1); ++var import_shim = require("use-sync-external-store/shim/index.js"); + var import_query_core = require("@tanstack/query-core"); + var import_QueryClientProvider = require("./QueryClientProvider.cjs"); + function useIsFetching(filters, queryClient) { + const client = (0, import_QueryClientProvider.useQueryClient)(queryClient); + const queryCache = client.getQueryCache(); +- return React.useSyncExternalStore( ++ return (0, import_shim.useSyncExternalStore)( + React.useCallback( + (onStoreChange) => queryCache.subscribe(import_query_core.notifyManager.batchCalls(onStoreChange)), + [queryCache] +diff --git a/build/modern/useIsFetching.cjs.map b/build/modern/useIsFetching.cjs.map +index 5a58e86806e2919b9dcfbaf0cc3c32a4e23a5661..d3d112b618dc78caf24b36510852fdd647381c0a 100644 +--- a/build/modern/useIsFetching.cjs.map ++++ b/build/modern/useIsFetching.cjs.map +@@ -1 +1 @@ +-{"version":3,"sources":["../../src/useIsFetching.ts"],"sourcesContent":["'use client'\nimport * as React from 'react'\nimport { notifyManager } from '@tanstack/query-core'\n\nimport { useQueryClient } from './QueryClientProvider'\nimport type { QueryClient, QueryFilters } from '@tanstack/query-core'\n\nexport function useIsFetching(\n filters?: QueryFilters,\n queryClient?: QueryClient,\n): number {\n const client = useQueryClient(queryClient)\n const queryCache = client.getQueryCache()\n\n return React.useSyncExternalStore(\n React.useCallback(\n (onStoreChange) =>\n queryCache.subscribe(notifyManager.batchCalls(onStoreChange)),\n [queryCache],\n ),\n () => client.isFetching(filters),\n () => client.isFetching(filters),\n )\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AACA,YAAuB;AACvB,wBAA8B;AAE9B,iCAA+B;AAGxB,SAAS,cACd,SACA,aACQ;AACR,QAAM,aAAS,2CAAe,WAAW;AACzC,QAAM,aAAa,OAAO,cAAc;AAExC,SAAa;AAAA,IACL;AAAA,MACJ,CAAC,kBACC,WAAW,UAAU,gCAAc,WAAW,aAAa,CAAC;AAAA,MAC9D,CAAC,UAAU;AAAA,IACb;AAAA,IACA,MAAM,OAAO,WAAW,OAAO;AAAA,IAC/B,MAAM,OAAO,WAAW,OAAO;AAAA,EACjC;AACF;","names":[]} +\ No newline at end of file ++{"version":3,"sources":["../../src/useIsFetching.ts"],"sourcesContent":["'use client'\nimport * as React from 'react'\nimport { useSyncExternalStore } from 'use-sync-external-store/shim/index.js'\n\nimport { notifyManager } from '@tanstack/query-core'\n\nimport { useQueryClient } from './QueryClientProvider'\nimport type { QueryClient, QueryFilters } from '@tanstack/query-core'\n\nexport function useIsFetching(\n filters?: QueryFilters,\n queryClient?: QueryClient,\n): number {\n const client = useQueryClient(queryClient)\n const queryCache = client.getQueryCache()\n\n return useSyncExternalStore(\n React.useCallback(\n (onStoreChange) =>\n queryCache.subscribe(notifyManager.batchCalls(onStoreChange)),\n [queryCache],\n ),\n () => client.isFetching(filters),\n () => client.isFetching(filters),\n )\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AACA,YAAuB;AACvB,kBAAqC;AAErC,wBAA8B;AAE9B,iCAA+B;AAGxB,SAAS,cACd,SACA,aACQ;AACR,QAAM,aAAS,2CAAe,WAAW;AACzC,QAAM,aAAa,OAAO,cAAc;AAExC,aAAO;AAAA,IACC;AAAA,MACJ,CAAC,kBACC,WAAW,UAAU,gCAAc,WAAW,aAAa,CAAC;AAAA,MAC9D,CAAC,UAAU;AAAA,IACb;AAAA,IACA,MAAM,OAAO,WAAW,OAAO;AAAA,IAC/B,MAAM,OAAO,WAAW,OAAO;AAAA,EACjC;AACF;","names":[]} +\ No newline at end of file +diff --git a/build/modern/useIsFetching.js b/build/modern/useIsFetching.js +index acfc67a302d371b13b632cfdfcba1740ac6cfa22..90af8d148cbedb97df0b11b64fe84b4db973acd4 100644 +--- a/build/modern/useIsFetching.js ++++ b/build/modern/useIsFetching.js +@@ -2,12 +2,13 @@ + + // src/useIsFetching.ts + import * as React from "react"; ++import { useSyncExternalStore } from "use-sync-external-store/shim/index.js"; + import { notifyManager } from "@tanstack/query-core"; + import { useQueryClient } from "./QueryClientProvider.js"; + function useIsFetching(filters, queryClient) { + const client = useQueryClient(queryClient); + const queryCache = client.getQueryCache(); +- return React.useSyncExternalStore( ++ return useSyncExternalStore( + React.useCallback( + (onStoreChange) => queryCache.subscribe(notifyManager.batchCalls(onStoreChange)), + [queryCache] +diff --git a/build/modern/useIsFetching.js.map b/build/modern/useIsFetching.js.map +index 9921ab6e20952d564197ef61fccc3ab1f4943bd0..4b13c50e8e70381758c583c3b8cfbd0180d13a04 100644 +--- a/build/modern/useIsFetching.js.map ++++ b/build/modern/useIsFetching.js.map +@@ -1 +1 @@ +-{"version":3,"sources":["../../src/useIsFetching.ts"],"sourcesContent":["'use client'\nimport * as React from 'react'\nimport { notifyManager } from '@tanstack/query-core'\n\nimport { useQueryClient } from './QueryClientProvider'\nimport type { QueryClient, QueryFilters } from '@tanstack/query-core'\n\nexport function useIsFetching(\n filters?: QueryFilters,\n queryClient?: QueryClient,\n): number {\n const client = useQueryClient(queryClient)\n const queryCache = client.getQueryCache()\n\n return React.useSyncExternalStore(\n React.useCallback(\n (onStoreChange) =>\n queryCache.subscribe(notifyManager.batchCalls(onStoreChange)),\n [queryCache],\n ),\n () => client.isFetching(filters),\n () => client.isFetching(filters),\n )\n}\n"],"mappings":";;;AACA,YAAY,WAAW;AACvB,SAAS,qBAAqB;AAE9B,SAAS,sBAAsB;AAGxB,SAAS,cACd,SACA,aACQ;AACR,QAAM,SAAS,eAAe,WAAW;AACzC,QAAM,aAAa,OAAO,cAAc;AAExC,SAAa;AAAA,IACL;AAAA,MACJ,CAAC,kBACC,WAAW,UAAU,cAAc,WAAW,aAAa,CAAC;AAAA,MAC9D,CAAC,UAAU;AAAA,IACb;AAAA,IACA,MAAM,OAAO,WAAW,OAAO;AAAA,IAC/B,MAAM,OAAO,WAAW,OAAO;AAAA,EACjC;AACF;","names":[]} +\ No newline at end of file ++{"version":3,"sources":["../../src/useIsFetching.ts"],"sourcesContent":["'use client'\nimport * as React from 'react'\nimport { useSyncExternalStore } from 'use-sync-external-store/shim/index.js'\n\nimport { notifyManager } from '@tanstack/query-core'\n\nimport { useQueryClient } from './QueryClientProvider'\nimport type { QueryClient, QueryFilters } from '@tanstack/query-core'\n\nexport function useIsFetching(\n filters?: QueryFilters,\n queryClient?: QueryClient,\n): number {\n const client = useQueryClient(queryClient)\n const queryCache = client.getQueryCache()\n\n return useSyncExternalStore(\n React.useCallback(\n (onStoreChange) =>\n queryCache.subscribe(notifyManager.batchCalls(onStoreChange)),\n [queryCache],\n ),\n () => client.isFetching(filters),\n () => client.isFetching(filters),\n )\n}\n"],"mappings":";;;AACA,YAAY,WAAW;AACvB,SAAS,4BAA4B;AAErC,SAAS,qBAAqB;AAE9B,SAAS,sBAAsB;AAGxB,SAAS,cACd,SACA,aACQ;AACR,QAAM,SAAS,eAAe,WAAW;AACzC,QAAM,aAAa,OAAO,cAAc;AAExC,SAAO;AAAA,IACC;AAAA,MACJ,CAAC,kBACC,WAAW,UAAU,cAAc,WAAW,aAAa,CAAC;AAAA,MAC9D,CAAC,UAAU;AAAA,IACb;AAAA,IACA,MAAM,OAAO,WAAW,OAAO;AAAA,IAC/B,MAAM,OAAO,WAAW,OAAO;AAAA,EACjC;AACF;","names":[]} +\ No newline at end of file +diff --git a/build/modern/useMutation.cjs b/build/modern/useMutation.cjs +index 175de467172e7c876d51141d22f151de482d2a43..826a83d5f08d22035d1f8bd31a0236299055dec3 100644 +--- a/build/modern/useMutation.cjs ++++ b/build/modern/useMutation.cjs +@@ -35,6 +35,7 @@ __export(useMutation_exports, { + }); + module.exports = __toCommonJS(useMutation_exports); + var React = __toESM(require("react"), 1); ++var import_shim = require("use-sync-external-store/shim/index.js"); + var import_query_core = require("@tanstack/query-core"); + var import_QueryClientProvider = require("./QueryClientProvider.cjs"); + var import_utils = require("./utils.cjs"); +@@ -49,7 +50,7 @@ function useMutation(options, queryClient) { + React.useEffect(() => { + observer.setOptions(options); + }, [observer, options]); +- const result = React.useSyncExternalStore( ++ const result = (0, import_shim.useSyncExternalStore)( + React.useCallback( + (onStoreChange) => observer.subscribe(import_query_core.notifyManager.batchCalls(onStoreChange)), + [observer] +diff --git a/build/modern/useMutation.cjs.map b/build/modern/useMutation.cjs.map +index 2beaf7a697d67be63bb22ae4739b0db0eeede8f7..ffd27eb4f52319afc1afa4122c9982f6484591bd 100644 +--- a/build/modern/useMutation.cjs.map ++++ b/build/modern/useMutation.cjs.map +@@ -1 +1 @@ +-{"version":3,"sources":["../../src/useMutation.ts"],"sourcesContent":["'use client'\nimport * as React from 'react'\nimport { MutationObserver, notifyManager } from '@tanstack/query-core'\nimport { useQueryClient } from './QueryClientProvider'\nimport { noop, shouldThrowError } from './utils'\nimport type {\n UseMutateFunction,\n UseMutationOptions,\n UseMutationResult,\n} from './types'\nimport type { DefaultError, QueryClient } from '@tanstack/query-core'\n\n// HOOK\n\nexport function useMutation<\n TData = unknown,\n TError = DefaultError,\n TVariables = void,\n TContext = unknown,\n>(\n options: UseMutationOptions,\n queryClient?: QueryClient,\n): UseMutationResult {\n const client = useQueryClient(queryClient)\n\n const [observer] = React.useState(\n () =>\n new MutationObserver(\n client,\n options,\n ),\n )\n\n React.useEffect(() => {\n observer.setOptions(options)\n }, [observer, options])\n\n const result = React.useSyncExternalStore(\n React.useCallback(\n (onStoreChange) =>\n observer.subscribe(notifyManager.batchCalls(onStoreChange)),\n [observer],\n ),\n () => observer.getCurrentResult(),\n () => observer.getCurrentResult(),\n )\n\n const mutate = React.useCallback<\n UseMutateFunction\n >(\n (variables, mutateOptions) => {\n observer.mutate(variables, mutateOptions).catch(noop)\n },\n [observer],\n )\n\n if (\n result.error &&\n shouldThrowError(observer.options.throwOnError, [result.error])\n ) {\n throw result.error\n }\n\n return { ...result, mutate, mutateAsync: result.mutate }\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AACA,YAAuB;AACvB,wBAAgD;AAChD,iCAA+B;AAC/B,mBAAuC;AAUhC,SAAS,YAMd,SACA,aACwD;AACxD,QAAM,aAAS,2CAAe,WAAW;AAEzC,QAAM,CAAC,QAAQ,IAAU;AAAA,IACvB,MACE,IAAI;AAAA,MACF;AAAA,MACA;AAAA,IACF;AAAA,EACJ;AAEA,EAAM,gBAAU,MAAM;AACpB,aAAS,WAAW,OAAO;AAAA,EAC7B,GAAG,CAAC,UAAU,OAAO,CAAC;AAEtB,QAAM,SAAe;AAAA,IACb;AAAA,MACJ,CAAC,kBACC,SAAS,UAAU,gCAAc,WAAW,aAAa,CAAC;AAAA,MAC5D,CAAC,QAAQ;AAAA,IACX;AAAA,IACA,MAAM,SAAS,iBAAiB;AAAA,IAChC,MAAM,SAAS,iBAAiB;AAAA,EAClC;AAEA,QAAM,SAAe;AAAA,IAGnB,CAAC,WAAW,kBAAkB;AAC5B,eAAS,OAAO,WAAW,aAAa,EAAE,MAAM,iBAAI;AAAA,IACtD;AAAA,IACA,CAAC,QAAQ;AAAA,EACX;AAEA,MACE,OAAO,aACP,+BAAiB,SAAS,QAAQ,cAAc,CAAC,OAAO,KAAK,CAAC,GAC9D;AACA,UAAM,OAAO;AAAA,EACf;AAEA,SAAO,EAAE,GAAG,QAAQ,QAAQ,aAAa,OAAO,OAAO;AACzD;","names":[]} +\ No newline at end of file ++{"version":3,"sources":["../../src/useMutation.ts"],"sourcesContent":["'use client'\nimport * as React from 'react'\nimport { useSyncExternalStore } from 'use-sync-external-store/shim/index.js'\n\nimport { MutationObserver, notifyManager } from '@tanstack/query-core'\nimport { useQueryClient } from './QueryClientProvider'\nimport { noop, shouldThrowError } from './utils'\nimport type {\n UseMutateFunction,\n UseMutationOptions,\n UseMutationResult,\n} from './types'\nimport type { DefaultError, QueryClient } from '@tanstack/query-core'\n\n// HOOK\n\nexport function useMutation<\n TData = unknown,\n TError = DefaultError,\n TVariables = void,\n TContext = unknown,\n>(\n options: UseMutationOptions,\n queryClient?: QueryClient,\n): UseMutationResult {\n const client = useQueryClient(queryClient)\n\n const [observer] = React.useState(\n () =>\n new MutationObserver(\n client,\n options,\n ),\n )\n\n React.useEffect(() => {\n observer.setOptions(options)\n }, [observer, options])\n\n const result = useSyncExternalStore(\n React.useCallback(\n (onStoreChange) =>\n observer.subscribe(notifyManager.batchCalls(onStoreChange)),\n [observer],\n ),\n () => observer.getCurrentResult(),\n () => observer.getCurrentResult(),\n )\n\n const mutate = React.useCallback<\n UseMutateFunction\n >(\n (variables, mutateOptions) => {\n observer.mutate(variables, mutateOptions).catch(noop)\n },\n [observer],\n )\n\n if (\n result.error &&\n shouldThrowError(observer.options.throwOnError, [result.error])\n ) {\n throw result.error\n }\n\n return { ...result, mutate, mutateAsync: result.mutate }\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AACA,YAAuB;AACvB,kBAAqC;AAErC,wBAAgD;AAChD,iCAA+B;AAC/B,mBAAuC;AAUhC,SAAS,YAMd,SACA,aACwD;AACxD,QAAM,aAAS,2CAAe,WAAW;AAEzC,QAAM,CAAC,QAAQ,IAAU;AAAA,IACvB,MACE,IAAI;AAAA,MACF;AAAA,MACA;AAAA,IACF;AAAA,EACJ;AAEA,EAAM,gBAAU,MAAM;AACpB,aAAS,WAAW,OAAO;AAAA,EAC7B,GAAG,CAAC,UAAU,OAAO,CAAC;AAEtB,QAAM,aAAS;AAAA,IACP;AAAA,MACJ,CAAC,kBACC,SAAS,UAAU,gCAAc,WAAW,aAAa,CAAC;AAAA,MAC5D,CAAC,QAAQ;AAAA,IACX;AAAA,IACA,MAAM,SAAS,iBAAiB;AAAA,IAChC,MAAM,SAAS,iBAAiB;AAAA,EAClC;AAEA,QAAM,SAAe;AAAA,IAGnB,CAAC,WAAW,kBAAkB;AAC5B,eAAS,OAAO,WAAW,aAAa,EAAE,MAAM,iBAAI;AAAA,IACtD;AAAA,IACA,CAAC,QAAQ;AAAA,EACX;AAEA,MACE,OAAO,aACP,+BAAiB,SAAS,QAAQ,cAAc,CAAC,OAAO,KAAK,CAAC,GAC9D;AACA,UAAM,OAAO;AAAA,EACf;AAEA,SAAO,EAAE,GAAG,QAAQ,QAAQ,aAAa,OAAO,OAAO;AACzD;","names":[]} +\ No newline at end of file +diff --git a/build/modern/useMutation.js b/build/modern/useMutation.js +index 515a3b92ecf8c348ccc7f16de4f778301327e9c9..a135e33b89a5cf9ef8d1725a9aada6283052bed9 100644 +--- a/build/modern/useMutation.js ++++ b/build/modern/useMutation.js +@@ -2,6 +2,7 @@ + + // src/useMutation.ts + import * as React from "react"; ++import { useSyncExternalStore } from "use-sync-external-store/shim/index.js"; + import { MutationObserver, notifyManager } from "@tanstack/query-core"; + import { useQueryClient } from "./QueryClientProvider.js"; + import { noop, shouldThrowError } from "./utils.js"; +@@ -16,7 +17,7 @@ function useMutation(options, queryClient) { + React.useEffect(() => { + observer.setOptions(options); + }, [observer, options]); +- const result = React.useSyncExternalStore( ++ const result = useSyncExternalStore( + React.useCallback( + (onStoreChange) => observer.subscribe(notifyManager.batchCalls(onStoreChange)), + [observer] +diff --git a/build/modern/useMutation.js.map b/build/modern/useMutation.js.map +index 0627ad75983fcc9d6cd9d66a20f7a935dd076ad4..03013010c6b9d825c2888d9ac03edc774e8b7965 100644 +--- a/build/modern/useMutation.js.map ++++ b/build/modern/useMutation.js.map +@@ -1 +1 @@ +-{"version":3,"sources":["../../src/useMutation.ts"],"sourcesContent":["'use client'\nimport * as React from 'react'\nimport { MutationObserver, notifyManager } from '@tanstack/query-core'\nimport { useQueryClient } from './QueryClientProvider'\nimport { noop, shouldThrowError } from './utils'\nimport type {\n UseMutateFunction,\n UseMutationOptions,\n UseMutationResult,\n} from './types'\nimport type { DefaultError, QueryClient } from '@tanstack/query-core'\n\n// HOOK\n\nexport function useMutation<\n TData = unknown,\n TError = DefaultError,\n TVariables = void,\n TContext = unknown,\n>(\n options: UseMutationOptions,\n queryClient?: QueryClient,\n): UseMutationResult {\n const client = useQueryClient(queryClient)\n\n const [observer] = React.useState(\n () =>\n new MutationObserver(\n client,\n options,\n ),\n )\n\n React.useEffect(() => {\n observer.setOptions(options)\n }, [observer, options])\n\n const result = React.useSyncExternalStore(\n React.useCallback(\n (onStoreChange) =>\n observer.subscribe(notifyManager.batchCalls(onStoreChange)),\n [observer],\n ),\n () => observer.getCurrentResult(),\n () => observer.getCurrentResult(),\n )\n\n const mutate = React.useCallback<\n UseMutateFunction\n >(\n (variables, mutateOptions) => {\n observer.mutate(variables, mutateOptions).catch(noop)\n },\n [observer],\n )\n\n if (\n result.error &&\n shouldThrowError(observer.options.throwOnError, [result.error])\n ) {\n throw result.error\n }\n\n return { ...result, mutate, mutateAsync: result.mutate }\n}\n"],"mappings":";;;AACA,YAAY,WAAW;AACvB,SAAS,kBAAkB,qBAAqB;AAChD,SAAS,sBAAsB;AAC/B,SAAS,MAAM,wBAAwB;AAUhC,SAAS,YAMd,SACA,aACwD;AACxD,QAAM,SAAS,eAAe,WAAW;AAEzC,QAAM,CAAC,QAAQ,IAAU;AAAA,IACvB,MACE,IAAI;AAAA,MACF;AAAA,MACA;AAAA,IACF;AAAA,EACJ;AAEA,EAAM,gBAAU,MAAM;AACpB,aAAS,WAAW,OAAO;AAAA,EAC7B,GAAG,CAAC,UAAU,OAAO,CAAC;AAEtB,QAAM,SAAe;AAAA,IACb;AAAA,MACJ,CAAC,kBACC,SAAS,UAAU,cAAc,WAAW,aAAa,CAAC;AAAA,MAC5D,CAAC,QAAQ;AAAA,IACX;AAAA,IACA,MAAM,SAAS,iBAAiB;AAAA,IAChC,MAAM,SAAS,iBAAiB;AAAA,EAClC;AAEA,QAAM,SAAe;AAAA,IAGnB,CAAC,WAAW,kBAAkB;AAC5B,eAAS,OAAO,WAAW,aAAa,EAAE,MAAM,IAAI;AAAA,IACtD;AAAA,IACA,CAAC,QAAQ;AAAA,EACX;AAEA,MACE,OAAO,SACP,iBAAiB,SAAS,QAAQ,cAAc,CAAC,OAAO,KAAK,CAAC,GAC9D;AACA,UAAM,OAAO;AAAA,EACf;AAEA,SAAO,EAAE,GAAG,QAAQ,QAAQ,aAAa,OAAO,OAAO;AACzD;","names":[]} +\ No newline at end of file ++{"version":3,"sources":["../../src/useMutation.ts"],"sourcesContent":["'use client'\nimport * as React from 'react'\nimport { useSyncExternalStore } from 'use-sync-external-store/shim/index.js'\n\nimport { MutationObserver, notifyManager } from '@tanstack/query-core'\nimport { useQueryClient } from './QueryClientProvider'\nimport { noop, shouldThrowError } from './utils'\nimport type {\n UseMutateFunction,\n UseMutationOptions,\n UseMutationResult,\n} from './types'\nimport type { DefaultError, QueryClient } from '@tanstack/query-core'\n\n// HOOK\n\nexport function useMutation<\n TData = unknown,\n TError = DefaultError,\n TVariables = void,\n TContext = unknown,\n>(\n options: UseMutationOptions,\n queryClient?: QueryClient,\n): UseMutationResult {\n const client = useQueryClient(queryClient)\n\n const [observer] = React.useState(\n () =>\n new MutationObserver(\n client,\n options,\n ),\n )\n\n React.useEffect(() => {\n observer.setOptions(options)\n }, [observer, options])\n\n const result = useSyncExternalStore(\n React.useCallback(\n (onStoreChange) =>\n observer.subscribe(notifyManager.batchCalls(onStoreChange)),\n [observer],\n ),\n () => observer.getCurrentResult(),\n () => observer.getCurrentResult(),\n )\n\n const mutate = React.useCallback<\n UseMutateFunction\n >(\n (variables, mutateOptions) => {\n observer.mutate(variables, mutateOptions).catch(noop)\n },\n [observer],\n )\n\n if (\n result.error &&\n shouldThrowError(observer.options.throwOnError, [result.error])\n ) {\n throw result.error\n }\n\n return { ...result, mutate, mutateAsync: result.mutate }\n}\n"],"mappings":";;;AACA,YAAY,WAAW;AACvB,SAAS,4BAA4B;AAErC,SAAS,kBAAkB,qBAAqB;AAChD,SAAS,sBAAsB;AAC/B,SAAS,MAAM,wBAAwB;AAUhC,SAAS,YAMd,SACA,aACwD;AACxD,QAAM,SAAS,eAAe,WAAW;AAEzC,QAAM,CAAC,QAAQ,IAAU;AAAA,IACvB,MACE,IAAI;AAAA,MACF;AAAA,MACA;AAAA,IACF;AAAA,EACJ;AAEA,EAAM,gBAAU,MAAM;AACpB,aAAS,WAAW,OAAO;AAAA,EAC7B,GAAG,CAAC,UAAU,OAAO,CAAC;AAEtB,QAAM,SAAS;AAAA,IACP;AAAA,MACJ,CAAC,kBACC,SAAS,UAAU,cAAc,WAAW,aAAa,CAAC;AAAA,MAC5D,CAAC,QAAQ;AAAA,IACX;AAAA,IACA,MAAM,SAAS,iBAAiB;AAAA,IAChC,MAAM,SAAS,iBAAiB;AAAA,EAClC;AAEA,QAAM,SAAe;AAAA,IAGnB,CAAC,WAAW,kBAAkB;AAC5B,eAAS,OAAO,WAAW,aAAa,EAAE,MAAM,IAAI;AAAA,IACtD;AAAA,IACA,CAAC,QAAQ;AAAA,EACX;AAEA,MACE,OAAO,SACP,iBAAiB,SAAS,QAAQ,cAAc,CAAC,OAAO,KAAK,CAAC,GAC9D;AACA,UAAM,OAAO;AAAA,EACf;AAEA,SAAO,EAAE,GAAG,QAAQ,QAAQ,aAAa,OAAO,OAAO;AACzD;","names":[]} +\ No newline at end of file +diff --git a/build/modern/useMutationState.cjs b/build/modern/useMutationState.cjs +index 0248bea1b0a0922589748a9338d85be66fc3468c..0bb6d8ac2eacb572b35c29429ef5d94edf33b7ad 100644 +--- a/build/modern/useMutationState.cjs ++++ b/build/modern/useMutationState.cjs +@@ -36,6 +36,7 @@ __export(useMutationState_exports, { + }); + module.exports = __toCommonJS(useMutationState_exports); + var React = __toESM(require("react"), 1); ++var import_shim = require("use-sync-external-store/shim/index.js"); + var import_query_core = require("@tanstack/query-core"); + var import_QueryClientProvider = require("./QueryClientProvider.cjs"); + function useIsMutating(filters, queryClient) { +@@ -60,7 +61,7 @@ function useMutationState(options = {}, queryClient) { + React.useEffect(() => { + optionsRef.current = options; + }); +- return React.useSyncExternalStore( ++ return (0, import_shim.useSyncExternalStore)( + React.useCallback( + (onStoreChange) => mutationCache.subscribe(() => { + const nextResult = (0, import_query_core.replaceEqualDeep)( +diff --git a/build/modern/useMutationState.cjs.map b/build/modern/useMutationState.cjs.map +index 68b0a392336cba75982a1146353c1e14698fca14..6383002ae8e9b97a4390db3bcead0e1955925ac6 100644 +--- a/build/modern/useMutationState.cjs.map ++++ b/build/modern/useMutationState.cjs.map +@@ -1 +1 @@ +-{"version":3,"sources":["../../src/useMutationState.ts"],"sourcesContent":["/* eslint-disable react-compiler/react-compiler */\n\n'use client'\nimport * as React from 'react'\n\nimport { notifyManager, replaceEqualDeep } from '@tanstack/query-core'\nimport { useQueryClient } from './QueryClientProvider'\nimport type {\n Mutation,\n MutationCache,\n MutationFilters,\n MutationState,\n QueryClient,\n} from '@tanstack/query-core'\n\nexport function useIsMutating(\n filters?: MutationFilters,\n queryClient?: QueryClient,\n): number {\n const client = useQueryClient(queryClient)\n return useMutationState(\n { filters: { ...filters, status: 'pending' } },\n client,\n ).length\n}\n\ntype MutationStateOptions = {\n filters?: MutationFilters\n select?: (mutation: Mutation) => TResult\n}\n\nfunction getResult(\n mutationCache: MutationCache,\n options: MutationStateOptions,\n): Array {\n return mutationCache\n .findAll(options.filters)\n .map(\n (mutation): TResult =>\n (options.select ? options.select(mutation) : mutation.state) as TResult,\n )\n}\n\nexport function useMutationState(\n options: MutationStateOptions = {},\n queryClient?: QueryClient,\n): Array {\n const mutationCache = useQueryClient(queryClient).getMutationCache()\n const optionsRef = React.useRef(options)\n const result = React.useRef>(null)\n if (!result.current) {\n result.current = getResult(mutationCache, options)\n }\n\n React.useEffect(() => {\n optionsRef.current = options\n })\n\n return React.useSyncExternalStore(\n React.useCallback(\n (onStoreChange) =>\n mutationCache.subscribe(() => {\n const nextResult = replaceEqualDeep(\n result.current,\n getResult(mutationCache, optionsRef.current),\n )\n if (result.current !== nextResult) {\n result.current = nextResult\n notifyManager.schedule(onStoreChange)\n }\n }),\n [mutationCache],\n ),\n () => result.current,\n () => result.current,\n )!\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAGA,YAAuB;AAEvB,wBAAgD;AAChD,iCAA+B;AASxB,SAAS,cACd,SACA,aACQ;AACR,QAAM,aAAS,2CAAe,WAAW;AACzC,SAAO;AAAA,IACL,EAAE,SAAS,EAAE,GAAG,SAAS,QAAQ,UAAU,EAAE;AAAA,IAC7C;AAAA,EACF,EAAE;AACJ;AAOA,SAAS,UACP,eACA,SACgB;AAChB,SAAO,cACJ,QAAQ,QAAQ,OAAO,EACvB;AAAA,IACC,CAAC,aACE,QAAQ,SAAS,QAAQ,OAAO,QAAQ,IAAI,SAAS;AAAA,EAC1D;AACJ;AAEO,SAAS,iBACd,UAAyC,CAAC,GAC1C,aACgB;AAChB,QAAM,oBAAgB,2CAAe,WAAW,EAAE,iBAAiB;AACnE,QAAM,aAAmB,aAAO,OAAO;AACvC,QAAM,SAAe,aAAuB,IAAI;AAChD,MAAI,CAAC,OAAO,SAAS;AACnB,WAAO,UAAU,UAAU,eAAe,OAAO;AAAA,EACnD;AAEA,EAAM,gBAAU,MAAM;AACpB,eAAW,UAAU;AAAA,EACvB,CAAC;AAED,SAAa;AAAA,IACL;AAAA,MACJ,CAAC,kBACC,cAAc,UAAU,MAAM;AAC5B,cAAM,iBAAa;AAAA,UACjB,OAAO;AAAA,UACP,UAAU,eAAe,WAAW,OAAO;AAAA,QAC7C;AACA,YAAI,OAAO,YAAY,YAAY;AACjC,iBAAO,UAAU;AACjB,0CAAc,SAAS,aAAa;AAAA,QACtC;AAAA,MACF,CAAC;AAAA,MACH,CAAC,aAAa;AAAA,IAChB;AAAA,IACA,MAAM,OAAO;AAAA,IACb,MAAM,OAAO;AAAA,EACf;AACF;","names":[]} +\ No newline at end of file ++{"version":3,"sources":["../../src/useMutationState.ts"],"sourcesContent":["/* eslint-disable react-compiler/react-compiler */\n\n'use client'\nimport * as React from 'react'\nimport { useSyncExternalStore } from 'use-sync-external-store/shim/index.js'\n\nimport { notifyManager, replaceEqualDeep } from '@tanstack/query-core'\nimport { useQueryClient } from './QueryClientProvider'\nimport type {\n Mutation,\n MutationCache,\n MutationFilters,\n MutationState,\n QueryClient,\n} from '@tanstack/query-core'\n\nexport function useIsMutating(\n filters?: MutationFilters,\n queryClient?: QueryClient,\n): number {\n const client = useQueryClient(queryClient)\n return useMutationState(\n { filters: { ...filters, status: 'pending' } },\n client,\n ).length\n}\n\ntype MutationStateOptions = {\n filters?: MutationFilters\n select?: (mutation: Mutation) => TResult\n}\n\nfunction getResult(\n mutationCache: MutationCache,\n options: MutationStateOptions,\n): Array {\n return mutationCache\n .findAll(options.filters)\n .map(\n (mutation): TResult =>\n (options.select ? options.select(mutation) : mutation.state) as TResult,\n )\n}\n\nexport function useMutationState(\n options: MutationStateOptions = {},\n queryClient?: QueryClient,\n): Array {\n const mutationCache = useQueryClient(queryClient).getMutationCache()\n const optionsRef = React.useRef(options)\n const result = React.useRef>(null)\n if (!result.current) {\n result.current = getResult(mutationCache, options)\n }\n\n React.useEffect(() => {\n optionsRef.current = options\n })\n\n return useSyncExternalStore(\n React.useCallback(\n (onStoreChange) =>\n mutationCache.subscribe(() => {\n const nextResult = replaceEqualDeep(\n result.current,\n getResult(mutationCache, optionsRef.current),\n )\n if (result.current !== nextResult) {\n result.current = nextResult\n notifyManager.schedule(onStoreChange)\n }\n }),\n [mutationCache],\n ),\n () => result.current,\n () => result.current,\n )!\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAGA,YAAuB;AACvB,kBAAqC;AAErC,wBAAgD;AAChD,iCAA+B;AASxB,SAAS,cACd,SACA,aACQ;AACR,QAAM,aAAS,2CAAe,WAAW;AACzC,SAAO;AAAA,IACL,EAAE,SAAS,EAAE,GAAG,SAAS,QAAQ,UAAU,EAAE;AAAA,IAC7C;AAAA,EACF,EAAE;AACJ;AAOA,SAAS,UACP,eACA,SACgB;AAChB,SAAO,cACJ,QAAQ,QAAQ,OAAO,EACvB;AAAA,IACC,CAAC,aACE,QAAQ,SAAS,QAAQ,OAAO,QAAQ,IAAI,SAAS;AAAA,EAC1D;AACJ;AAEO,SAAS,iBACd,UAAyC,CAAC,GAC1C,aACgB;AAChB,QAAM,oBAAgB,2CAAe,WAAW,EAAE,iBAAiB;AACnE,QAAM,aAAmB,aAAO,OAAO;AACvC,QAAM,SAAe,aAAuB,IAAI;AAChD,MAAI,CAAC,OAAO,SAAS;AACnB,WAAO,UAAU,UAAU,eAAe,OAAO;AAAA,EACnD;AAEA,EAAM,gBAAU,MAAM;AACpB,eAAW,UAAU;AAAA,EACvB,CAAC;AAED,aAAO;AAAA,IACC;AAAA,MACJ,CAAC,kBACC,cAAc,UAAU,MAAM;AAC5B,cAAM,iBAAa;AAAA,UACjB,OAAO;AAAA,UACP,UAAU,eAAe,WAAW,OAAO;AAAA,QAC7C;AACA,YAAI,OAAO,YAAY,YAAY;AACjC,iBAAO,UAAU;AACjB,0CAAc,SAAS,aAAa;AAAA,QACtC;AAAA,MACF,CAAC;AAAA,MACH,CAAC,aAAa;AAAA,IAChB;AAAA,IACA,MAAM,OAAO;AAAA,IACb,MAAM,OAAO;AAAA,EACf;AACF;","names":[]} +\ No newline at end of file +diff --git a/build/modern/useMutationState.js b/build/modern/useMutationState.js +index 0648af4cfd70499f3365abc8b63a06e06976f793..2345f0eecff02f33f0354832b94ce0fdfa31540e 100644 +--- a/build/modern/useMutationState.js ++++ b/build/modern/useMutationState.js +@@ -2,6 +2,7 @@ + + // src/useMutationState.ts + import * as React from "react"; ++import { useSyncExternalStore } from "use-sync-external-store/shim/index.js"; + import { notifyManager, replaceEqualDeep } from "@tanstack/query-core"; + import { useQueryClient } from "./QueryClientProvider.js"; + function useIsMutating(filters, queryClient) { +@@ -26,7 +27,7 @@ function useMutationState(options = {}, queryClient) { + React.useEffect(() => { + optionsRef.current = options; + }); +- return React.useSyncExternalStore( ++ return useSyncExternalStore( + React.useCallback( + (onStoreChange) => mutationCache.subscribe(() => { + const nextResult = replaceEqualDeep( +diff --git a/build/modern/useMutationState.js.map b/build/modern/useMutationState.js.map +index ae13415e7f9c31177b3ccd37a92ba91b10385705..aa4027b3c846be5f0f769339aee4ff1ac2c0de82 100644 +--- a/build/modern/useMutationState.js.map ++++ b/build/modern/useMutationState.js.map +@@ -1 +1 @@ +-{"version":3,"sources":["../../src/useMutationState.ts"],"sourcesContent":["/* eslint-disable react-compiler/react-compiler */\n\n'use client'\nimport * as React from 'react'\n\nimport { notifyManager, replaceEqualDeep } from '@tanstack/query-core'\nimport { useQueryClient } from './QueryClientProvider'\nimport type {\n Mutation,\n MutationCache,\n MutationFilters,\n MutationState,\n QueryClient,\n} from '@tanstack/query-core'\n\nexport function useIsMutating(\n filters?: MutationFilters,\n queryClient?: QueryClient,\n): number {\n const client = useQueryClient(queryClient)\n return useMutationState(\n { filters: { ...filters, status: 'pending' } },\n client,\n ).length\n}\n\ntype MutationStateOptions = {\n filters?: MutationFilters\n select?: (mutation: Mutation) => TResult\n}\n\nfunction getResult(\n mutationCache: MutationCache,\n options: MutationStateOptions,\n): Array {\n return mutationCache\n .findAll(options.filters)\n .map(\n (mutation): TResult =>\n (options.select ? options.select(mutation) : mutation.state) as TResult,\n )\n}\n\nexport function useMutationState(\n options: MutationStateOptions = {},\n queryClient?: QueryClient,\n): Array {\n const mutationCache = useQueryClient(queryClient).getMutationCache()\n const optionsRef = React.useRef(options)\n const result = React.useRef>(null)\n if (!result.current) {\n result.current = getResult(mutationCache, options)\n }\n\n React.useEffect(() => {\n optionsRef.current = options\n })\n\n return React.useSyncExternalStore(\n React.useCallback(\n (onStoreChange) =>\n mutationCache.subscribe(() => {\n const nextResult = replaceEqualDeep(\n result.current,\n getResult(mutationCache, optionsRef.current),\n )\n if (result.current !== nextResult) {\n result.current = nextResult\n notifyManager.schedule(onStoreChange)\n }\n }),\n [mutationCache],\n ),\n () => result.current,\n () => result.current,\n )!\n}\n"],"mappings":";;;AAGA,YAAY,WAAW;AAEvB,SAAS,eAAe,wBAAwB;AAChD,SAAS,sBAAsB;AASxB,SAAS,cACd,SACA,aACQ;AACR,QAAM,SAAS,eAAe,WAAW;AACzC,SAAO;AAAA,IACL,EAAE,SAAS,EAAE,GAAG,SAAS,QAAQ,UAAU,EAAE;AAAA,IAC7C;AAAA,EACF,EAAE;AACJ;AAOA,SAAS,UACP,eACA,SACgB;AAChB,SAAO,cACJ,QAAQ,QAAQ,OAAO,EACvB;AAAA,IACC,CAAC,aACE,QAAQ,SAAS,QAAQ,OAAO,QAAQ,IAAI,SAAS;AAAA,EAC1D;AACJ;AAEO,SAAS,iBACd,UAAyC,CAAC,GAC1C,aACgB;AAChB,QAAM,gBAAgB,eAAe,WAAW,EAAE,iBAAiB;AACnE,QAAM,aAAmB,aAAO,OAAO;AACvC,QAAM,SAAe,aAAuB,IAAI;AAChD,MAAI,CAAC,OAAO,SAAS;AACnB,WAAO,UAAU,UAAU,eAAe,OAAO;AAAA,EACnD;AAEA,EAAM,gBAAU,MAAM;AACpB,eAAW,UAAU;AAAA,EACvB,CAAC;AAED,SAAa;AAAA,IACL;AAAA,MACJ,CAAC,kBACC,cAAc,UAAU,MAAM;AAC5B,cAAM,aAAa;AAAA,UACjB,OAAO;AAAA,UACP,UAAU,eAAe,WAAW,OAAO;AAAA,QAC7C;AACA,YAAI,OAAO,YAAY,YAAY;AACjC,iBAAO,UAAU;AACjB,wBAAc,SAAS,aAAa;AAAA,QACtC;AAAA,MACF,CAAC;AAAA,MACH,CAAC,aAAa;AAAA,IAChB;AAAA,IACA,MAAM,OAAO;AAAA,IACb,MAAM,OAAO;AAAA,EACf;AACF;","names":[]} +\ No newline at end of file ++{"version":3,"sources":["../../src/useMutationState.ts"],"sourcesContent":["/* eslint-disable react-compiler/react-compiler */\n\n'use client'\nimport * as React from 'react'\nimport { useSyncExternalStore } from 'use-sync-external-store/shim/index.js'\n\nimport { notifyManager, replaceEqualDeep } from '@tanstack/query-core'\nimport { useQueryClient } from './QueryClientProvider'\nimport type {\n Mutation,\n MutationCache,\n MutationFilters,\n MutationState,\n QueryClient,\n} from '@tanstack/query-core'\n\nexport function useIsMutating(\n filters?: MutationFilters,\n queryClient?: QueryClient,\n): number {\n const client = useQueryClient(queryClient)\n return useMutationState(\n { filters: { ...filters, status: 'pending' } },\n client,\n ).length\n}\n\ntype MutationStateOptions = {\n filters?: MutationFilters\n select?: (mutation: Mutation) => TResult\n}\n\nfunction getResult(\n mutationCache: MutationCache,\n options: MutationStateOptions,\n): Array {\n return mutationCache\n .findAll(options.filters)\n .map(\n (mutation): TResult =>\n (options.select ? options.select(mutation) : mutation.state) as TResult,\n )\n}\n\nexport function useMutationState(\n options: MutationStateOptions = {},\n queryClient?: QueryClient,\n): Array {\n const mutationCache = useQueryClient(queryClient).getMutationCache()\n const optionsRef = React.useRef(options)\n const result = React.useRef>(null)\n if (!result.current) {\n result.current = getResult(mutationCache, options)\n }\n\n React.useEffect(() => {\n optionsRef.current = options\n })\n\n return useSyncExternalStore(\n React.useCallback(\n (onStoreChange) =>\n mutationCache.subscribe(() => {\n const nextResult = replaceEqualDeep(\n result.current,\n getResult(mutationCache, optionsRef.current),\n )\n if (result.current !== nextResult) {\n result.current = nextResult\n notifyManager.schedule(onStoreChange)\n }\n }),\n [mutationCache],\n ),\n () => result.current,\n () => result.current,\n )!\n}\n"],"mappings":";;;AAGA,YAAY,WAAW;AACvB,SAAS,4BAA4B;AAErC,SAAS,eAAe,wBAAwB;AAChD,SAAS,sBAAsB;AASxB,SAAS,cACd,SACA,aACQ;AACR,QAAM,SAAS,eAAe,WAAW;AACzC,SAAO;AAAA,IACL,EAAE,SAAS,EAAE,GAAG,SAAS,QAAQ,UAAU,EAAE;AAAA,IAC7C;AAAA,EACF,EAAE;AACJ;AAOA,SAAS,UACP,eACA,SACgB;AAChB,SAAO,cACJ,QAAQ,QAAQ,OAAO,EACvB;AAAA,IACC,CAAC,aACE,QAAQ,SAAS,QAAQ,OAAO,QAAQ,IAAI,SAAS;AAAA,EAC1D;AACJ;AAEO,SAAS,iBACd,UAAyC,CAAC,GAC1C,aACgB;AAChB,QAAM,gBAAgB,eAAe,WAAW,EAAE,iBAAiB;AACnE,QAAM,aAAmB,aAAO,OAAO;AACvC,QAAM,SAAe,aAAuB,IAAI;AAChD,MAAI,CAAC,OAAO,SAAS;AACnB,WAAO,UAAU,UAAU,eAAe,OAAO;AAAA,EACnD;AAEA,EAAM,gBAAU,MAAM;AACpB,eAAW,UAAU;AAAA,EACvB,CAAC;AAED,SAAO;AAAA,IACC;AAAA,MACJ,CAAC,kBACC,cAAc,UAAU,MAAM;AAC5B,cAAM,aAAa;AAAA,UACjB,OAAO;AAAA,UACP,UAAU,eAAe,WAAW,OAAO;AAAA,QAC7C;AACA,YAAI,OAAO,YAAY,YAAY;AACjC,iBAAO,UAAU;AACjB,wBAAc,SAAS,aAAa;AAAA,QACtC;AAAA,MACF,CAAC;AAAA,MACH,CAAC,aAAa;AAAA,IAChB;AAAA,IACA,MAAM,OAAO;AAAA,IACb,MAAM,OAAO;AAAA,EACf;AACF;","names":[]} +\ No newline at end of file +diff --git a/build/modern/useQueries.cjs b/build/modern/useQueries.cjs +index a3be327942dfeb675da9da9308a4e21d7c29704c..91f094199c71a83c54198726eb18233b66f56171 100644 +--- a/build/modern/useQueries.cjs ++++ b/build/modern/useQueries.cjs +@@ -35,6 +35,7 @@ __export(useQueries_exports, { + }); + module.exports = __toCommonJS(useQueries_exports); + var React = __toESM(require("react"), 1); ++var import_shim = require("use-sync-external-store/shim/index.js"); + var import_query_core = require("@tanstack/query-core"); + var import_QueryClientProvider = require("./QueryClientProvider.cjs"); + var import_isRestoring = require("./isRestoring.cjs"); +@@ -75,7 +76,7 @@ function useQueries({ + defaultedQueries, + options.combine + ); +- React.useSyncExternalStore( ++ (0, import_shim.useSyncExternalStore)( + React.useCallback( + (onStoreChange) => isRestoring ? import_utils.noop : observer.subscribe(import_query_core.notifyManager.batchCalls(onStoreChange)), + [observer, isRestoring] +diff --git a/build/modern/useQueries.cjs.map b/build/modern/useQueries.cjs.map +index a6403e666c754b1bf351a8553556e6628c61ac30..5a4b7ef9d50310739f8b02562da0ad6dd676693b 100644 +--- a/build/modern/useQueries.cjs.map ++++ b/build/modern/useQueries.cjs.map +@@ -1 +1 @@ +-{"version":3,"sources":["../../src/useQueries.ts"],"sourcesContent":["'use client'\nimport * as React from 'react'\n\nimport {\n QueriesObserver,\n QueryObserver,\n notifyManager,\n} from '@tanstack/query-core'\nimport { useQueryClient } from './QueryClientProvider'\nimport { useIsRestoring } from './isRestoring'\nimport { useQueryErrorResetBoundary } from './QueryErrorResetBoundary'\nimport {\n ensurePreventErrorBoundaryRetry,\n getHasError,\n useClearResetErrorBoundary,\n} from './errorBoundaryUtils'\nimport {\n ensureSuspenseTimers,\n fetchOptimistic,\n shouldSuspend,\n willFetch,\n} from './suspense'\nimport { noop } from './utils'\nimport type {\n DefinedUseQueryResult,\n UseQueryOptions,\n UseQueryResult,\n} from './types'\nimport type {\n DefaultError,\n OmitKeyof,\n QueriesObserverOptions,\n QueriesPlaceholderDataFunction,\n QueryClient,\n QueryFunction,\n QueryKey,\n QueryObserverOptions,\n ThrowOnError,\n} from '@tanstack/query-core'\n\n// This defines the `UseQueryOptions` that are accepted in `QueriesOptions` & `GetOptions`.\n// `placeholderData` function always gets undefined passed\ntype UseQueryOptionsForUseQueries<\n TQueryFnData = unknown,\n TError = DefaultError,\n TData = TQueryFnData,\n TQueryKey extends QueryKey = QueryKey,\n> = OmitKeyof<\n UseQueryOptions,\n 'placeholderData'\n> & {\n placeholderData?: TQueryFnData | QueriesPlaceholderDataFunction\n}\n\n// Avoid TS depth-limit error in case of large array literal\ntype MAXIMUM_DEPTH = 20\n\n// Widen the type of the symbol to enable type inference even if skipToken is not immutable.\ntype SkipTokenForUseQueries = symbol\n\ntype GetUseQueryOptionsForUseQueries =\n // Part 1: responsible for applying explicit type parameter to function arguments, if object { queryFnData: TQueryFnData, error: TError, data: TData }\n T extends {\n queryFnData: infer TQueryFnData\n error?: infer TError\n data: infer TData\n }\n ? UseQueryOptionsForUseQueries\n : T extends { queryFnData: infer TQueryFnData; error?: infer TError }\n ? UseQueryOptionsForUseQueries\n : T extends { data: infer TData; error?: infer TError }\n ? UseQueryOptionsForUseQueries\n : // Part 2: responsible for applying explicit type parameter to function arguments, if tuple [TQueryFnData, TError, TData]\n T extends [infer TQueryFnData, infer TError, infer TData]\n ? UseQueryOptionsForUseQueries\n : T extends [infer TQueryFnData, infer TError]\n ? UseQueryOptionsForUseQueries\n : T extends [infer TQueryFnData]\n ? UseQueryOptionsForUseQueries\n : // Part 3: responsible for inferring and enforcing type if no explicit parameter was provided\n T extends {\n queryFn?:\n | QueryFunction\n | SkipTokenForUseQueries\n select?: (data: any) => infer TData\n throwOnError?: ThrowOnError\n }\n ? UseQueryOptionsForUseQueries<\n TQueryFnData,\n unknown extends TError ? DefaultError : TError,\n unknown extends TData ? TQueryFnData : TData,\n TQueryKey\n >\n : // Fallback\n UseQueryOptionsForUseQueries\n\n// A defined initialData setting should return a DefinedUseQueryResult rather than UseQueryResult\ntype GetDefinedOrUndefinedQueryResult = T extends {\n initialData?: infer TInitialData\n}\n ? unknown extends TInitialData\n ? UseQueryResult\n : TInitialData extends TData\n ? DefinedUseQueryResult\n : TInitialData extends () => infer TInitialDataResult\n ? unknown extends TInitialDataResult\n ? UseQueryResult\n : TInitialDataResult extends TData\n ? DefinedUseQueryResult\n : UseQueryResult\n : UseQueryResult\n : UseQueryResult\n\ntype GetUseQueryResult =\n // Part 1: responsible for mapping explicit type parameter to function result, if object\n T extends { queryFnData: any; error?: infer TError; data: infer TData }\n ? GetDefinedOrUndefinedQueryResult\n : T extends { queryFnData: infer TQueryFnData; error?: infer TError }\n ? GetDefinedOrUndefinedQueryResult\n : T extends { data: infer TData; error?: infer TError }\n ? GetDefinedOrUndefinedQueryResult\n : // Part 2: responsible for mapping explicit type parameter to function result, if tuple\n T extends [any, infer TError, infer TData]\n ? GetDefinedOrUndefinedQueryResult\n : T extends [infer TQueryFnData, infer TError]\n ? GetDefinedOrUndefinedQueryResult\n : T extends [infer TQueryFnData]\n ? GetDefinedOrUndefinedQueryResult\n : // Part 3: responsible for mapping inferred type to results, if no explicit parameter was provided\n T extends {\n queryFn?:\n | QueryFunction\n | SkipTokenForUseQueries\n select?: (data: any) => infer TData\n throwOnError?: ThrowOnError\n }\n ? GetDefinedOrUndefinedQueryResult<\n T,\n unknown extends TData ? TQueryFnData : TData,\n unknown extends TError ? DefaultError : TError\n >\n : // Fallback\n UseQueryResult\n\n/**\n * QueriesOptions reducer recursively unwraps function arguments to infer/enforce type param\n */\nexport type QueriesOptions<\n T extends Array,\n TResults extends Array = [],\n TDepth extends ReadonlyArray = [],\n> = TDepth['length'] extends MAXIMUM_DEPTH\n ? Array\n : T extends []\n ? []\n : T extends [infer Head]\n ? [...TResults, GetUseQueryOptionsForUseQueries]\n : T extends [infer Head, ...infer Tails]\n ? QueriesOptions<\n [...Tails],\n [...TResults, GetUseQueryOptionsForUseQueries],\n [...TDepth, 1]\n >\n : ReadonlyArray extends T\n ? T\n : // If T is *some* array but we couldn't assign unknown[] to it, then it must hold some known/homogenous type!\n // use this to infer the param types in the case of Array.map() argument\n T extends Array<\n UseQueryOptionsForUseQueries<\n infer TQueryFnData,\n infer TError,\n infer TData,\n infer TQueryKey\n >\n >\n ? Array<\n UseQueryOptionsForUseQueries<\n TQueryFnData,\n TError,\n TData,\n TQueryKey\n >\n >\n : // Fallback\n Array\n\n/**\n * QueriesResults reducer recursively maps type param to results\n */\nexport type QueriesResults<\n T extends Array,\n TResults extends Array = [],\n TDepth extends ReadonlyArray = [],\n> = TDepth['length'] extends MAXIMUM_DEPTH\n ? Array\n : T extends []\n ? []\n : T extends [infer Head]\n ? [...TResults, GetUseQueryResult]\n : T extends [infer Head, ...infer Tails]\n ? QueriesResults<\n [...Tails],\n [...TResults, GetUseQueryResult],\n [...TDepth, 1]\n >\n : T extends Array<\n UseQueryOptionsForUseQueries<\n infer TQueryFnData,\n infer TError,\n infer TData,\n any\n >\n >\n ? // Dynamic-size (homogenous) UseQueryOptions array: map directly to array of results\n Array<\n UseQueryResult<\n unknown extends TData ? TQueryFnData : TData,\n unknown extends TError ? DefaultError : TError\n >\n >\n : // Fallback\n Array\n\nexport function useQueries<\n T extends Array,\n TCombinedResult = QueriesResults,\n>(\n {\n queries,\n ...options\n }: {\n queries: readonly [...QueriesOptions]\n combine?: (result: QueriesResults) => TCombinedResult\n },\n queryClient?: QueryClient,\n): TCombinedResult {\n const client = useQueryClient(queryClient)\n const isRestoring = useIsRestoring()\n const errorResetBoundary = useQueryErrorResetBoundary()\n\n const defaultedQueries = React.useMemo(\n () =>\n queries.map((opts) => {\n const defaultedOptions = client.defaultQueryOptions(\n opts as QueryObserverOptions,\n )\n\n // Make sure the results are already in fetching state before subscribing or updating options\n defaultedOptions._optimisticResults = isRestoring\n ? 'isRestoring'\n : 'optimistic'\n\n return defaultedOptions\n }),\n [queries, client, isRestoring],\n )\n\n defaultedQueries.forEach((query) => {\n ensureSuspenseTimers(query)\n ensurePreventErrorBoundaryRetry(query, errorResetBoundary)\n })\n\n useClearResetErrorBoundary(errorResetBoundary)\n\n const [observer] = React.useState(\n () =>\n new QueriesObserver(\n client,\n defaultedQueries,\n options as QueriesObserverOptions,\n ),\n )\n\n const [optimisticResult, getCombinedResult, trackResult] =\n observer.getOptimisticResult(\n defaultedQueries,\n (options as QueriesObserverOptions).combine,\n )\n\n React.useSyncExternalStore(\n React.useCallback(\n (onStoreChange) =>\n isRestoring\n ? noop\n : observer.subscribe(notifyManager.batchCalls(onStoreChange)),\n [observer, isRestoring],\n ),\n () => observer.getCurrentResult(),\n () => observer.getCurrentResult(),\n )\n\n React.useEffect(() => {\n // Do not notify on updates because of changes in the options because\n // these changes should already be reflected in the optimistic result.\n observer.setQueries(\n defaultedQueries,\n options as QueriesObserverOptions,\n {\n listeners: false,\n },\n )\n }, [defaultedQueries, options, observer])\n\n const shouldAtLeastOneSuspend = optimisticResult.some((result, index) =>\n shouldSuspend(defaultedQueries[index], result),\n )\n\n const suspensePromises = shouldAtLeastOneSuspend\n ? optimisticResult.flatMap((result, index) => {\n const opts = defaultedQueries[index]\n\n if (opts) {\n const queryObserver = new QueryObserver(client, opts)\n if (shouldSuspend(opts, result)) {\n return fetchOptimistic(opts, queryObserver, errorResetBoundary)\n } else if (willFetch(result, isRestoring)) {\n void fetchOptimistic(opts, queryObserver, errorResetBoundary)\n }\n }\n return []\n })\n : []\n\n if (suspensePromises.length > 0) {\n throw Promise.all(suspensePromises)\n }\n const firstSingleResultWhichShouldThrow = optimisticResult.find(\n (result, index) => {\n const query = defaultedQueries[index]\n return (\n query &&\n getHasError({\n result,\n errorResetBoundary,\n throwOnError: query.throwOnError,\n query: client.getQueryCache().get(query.queryHash),\n })\n )\n },\n )\n\n if (firstSingleResultWhichShouldThrow?.error) {\n throw firstSingleResultWhichShouldThrow.error\n }\n\n return getCombinedResult(trackResult())\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AACA,YAAuB;AAEvB,wBAIO;AACP,iCAA+B;AAC/B,yBAA+B;AAC/B,qCAA2C;AAC3C,gCAIO;AACP,sBAKO;AACP,mBAAqB;AAyMd,SAAS,WAId;AAAA,EACE;AAAA,EACA,GAAG;AACL,GAIA,aACiB;AACjB,QAAM,aAAS,2CAAe,WAAW;AACzC,QAAM,kBAAc,mCAAe;AACnC,QAAM,yBAAqB,2DAA2B;AAEtD,QAAM,mBAAyB;AAAA,IAC7B,MACE,QAAQ,IAAI,CAAC,SAAS;AACpB,YAAM,mBAAmB,OAAO;AAAA,QAC9B;AAAA,MACF;AAGA,uBAAiB,qBAAqB,cAClC,gBACA;AAEJ,aAAO;AAAA,IACT,CAAC;AAAA,IACH,CAAC,SAAS,QAAQ,WAAW;AAAA,EAC/B;AAEA,mBAAiB,QAAQ,CAAC,UAAU;AAClC,8CAAqB,KAAK;AAC1B,mEAAgC,OAAO,kBAAkB;AAAA,EAC3D,CAAC;AAED,4DAA2B,kBAAkB;AAE7C,QAAM,CAAC,QAAQ,IAAU;AAAA,IACvB,MACE,IAAI;AAAA,MACF;AAAA,MACA;AAAA,MACA;AAAA,IACF;AAAA,EACJ;AAEA,QAAM,CAAC,kBAAkB,mBAAmB,WAAW,IACrD,SAAS;AAAA,IACP;AAAA,IACC,QAAoD;AAAA,EACvD;AAEF,EAAM;AAAA,IACE;AAAA,MACJ,CAAC,kBACC,cACI,oBACA,SAAS,UAAU,gCAAc,WAAW,aAAa,CAAC;AAAA,MAChE,CAAC,UAAU,WAAW;AAAA,IACxB;AAAA,IACA,MAAM,SAAS,iBAAiB;AAAA,IAChC,MAAM,SAAS,iBAAiB;AAAA,EAClC;AAEA,EAAM,gBAAU,MAAM;AAGpB,aAAS;AAAA,MACP;AAAA,MACA;AAAA,MACA;AAAA,QACE,WAAW;AAAA,MACb;AAAA,IACF;AAAA,EACF,GAAG,CAAC,kBAAkB,SAAS,QAAQ,CAAC;AAExC,QAAM,0BAA0B,iBAAiB;AAAA,IAAK,CAAC,QAAQ,cAC7D,+BAAc,iBAAiB,KAAK,GAAG,MAAM;AAAA,EAC/C;AAEA,QAAM,mBAAmB,0BACrB,iBAAiB,QAAQ,CAAC,QAAQ,UAAU;AAC1C,UAAM,OAAO,iBAAiB,KAAK;AAEnC,QAAI,MAAM;AACR,YAAM,gBAAgB,IAAI,gCAAc,QAAQ,IAAI;AACpD,cAAI,+BAAc,MAAM,MAAM,GAAG;AAC/B,mBAAO,iCAAgB,MAAM,eAAe,kBAAkB;AAAA,MAChE,eAAW,2BAAU,QAAQ,WAAW,GAAG;AACzC,iBAAK,iCAAgB,MAAM,eAAe,kBAAkB;AAAA,MAC9D;AAAA,IACF;AACA,WAAO,CAAC;AAAA,EACV,CAAC,IACD,CAAC;AAEL,MAAI,iBAAiB,SAAS,GAAG;AAC/B,UAAM,QAAQ,IAAI,gBAAgB;AAAA,EACpC;AACA,QAAM,oCAAoC,iBAAiB;AAAA,IACzD,CAAC,QAAQ,UAAU;AACjB,YAAM,QAAQ,iBAAiB,KAAK;AACpC,aACE,aACA,uCAAY;AAAA,QACV;AAAA,QACA;AAAA,QACA,cAAc,MAAM;AAAA,QACpB,OAAO,OAAO,cAAc,EAAE,IAAI,MAAM,SAAS;AAAA,MACnD,CAAC;AAAA,IAEL;AAAA,EACF;AAEA,MAAI,mCAAmC,OAAO;AAC5C,UAAM,kCAAkC;AAAA,EAC1C;AAEA,SAAO,kBAAkB,YAAY,CAAC;AACxC;","names":[]} +\ No newline at end of file ++{"version":3,"sources":["../../src/useQueries.ts"],"sourcesContent":["'use client'\nimport * as React from 'react'\nimport { useSyncExternalStore } from 'use-sync-external-store/shim/index.js'\n\nimport {\n QueriesObserver,\n QueryObserver,\n notifyManager,\n} from '@tanstack/query-core'\nimport { useQueryClient } from './QueryClientProvider'\nimport { useIsRestoring } from './isRestoring'\nimport { useQueryErrorResetBoundary } from './QueryErrorResetBoundary'\nimport {\n ensurePreventErrorBoundaryRetry,\n getHasError,\n useClearResetErrorBoundary,\n} from './errorBoundaryUtils'\nimport {\n ensureSuspenseTimers,\n fetchOptimistic,\n shouldSuspend,\n willFetch,\n} from './suspense'\nimport { noop } from './utils'\nimport type {\n DefinedUseQueryResult,\n UseQueryOptions,\n UseQueryResult,\n} from './types'\nimport type {\n DefaultError,\n OmitKeyof,\n QueriesObserverOptions,\n QueriesPlaceholderDataFunction,\n QueryClient,\n QueryFunction,\n QueryKey,\n QueryObserverOptions,\n ThrowOnError,\n} from '@tanstack/query-core'\n\n// This defines the `UseQueryOptions` that are accepted in `QueriesOptions` & `GetOptions`.\n// `placeholderData` function always gets undefined passed\ntype UseQueryOptionsForUseQueries<\n TQueryFnData = unknown,\n TError = DefaultError,\n TData = TQueryFnData,\n TQueryKey extends QueryKey = QueryKey,\n> = OmitKeyof<\n UseQueryOptions,\n 'placeholderData'\n> & {\n placeholderData?: TQueryFnData | QueriesPlaceholderDataFunction\n}\n\n// Avoid TS depth-limit error in case of large array literal\ntype MAXIMUM_DEPTH = 20\n\n// Widen the type of the symbol to enable type inference even if skipToken is not immutable.\ntype SkipTokenForUseQueries = symbol\n\ntype GetUseQueryOptionsForUseQueries =\n // Part 1: responsible for applying explicit type parameter to function arguments, if object { queryFnData: TQueryFnData, error: TError, data: TData }\n T extends {\n queryFnData: infer TQueryFnData\n error?: infer TError\n data: infer TData\n }\n ? UseQueryOptionsForUseQueries\n : T extends { queryFnData: infer TQueryFnData; error?: infer TError }\n ? UseQueryOptionsForUseQueries\n : T extends { data: infer TData; error?: infer TError }\n ? UseQueryOptionsForUseQueries\n : // Part 2: responsible for applying explicit type parameter to function arguments, if tuple [TQueryFnData, TError, TData]\n T extends [infer TQueryFnData, infer TError, infer TData]\n ? UseQueryOptionsForUseQueries\n : T extends [infer TQueryFnData, infer TError]\n ? UseQueryOptionsForUseQueries\n : T extends [infer TQueryFnData]\n ? UseQueryOptionsForUseQueries\n : // Part 3: responsible for inferring and enforcing type if no explicit parameter was provided\n T extends {\n queryFn?:\n | QueryFunction\n | SkipTokenForUseQueries\n select?: (data: any) => infer TData\n throwOnError?: ThrowOnError\n }\n ? UseQueryOptionsForUseQueries<\n TQueryFnData,\n unknown extends TError ? DefaultError : TError,\n unknown extends TData ? TQueryFnData : TData,\n TQueryKey\n >\n : // Fallback\n UseQueryOptionsForUseQueries\n\n// A defined initialData setting should return a DefinedUseQueryResult rather than UseQueryResult\ntype GetDefinedOrUndefinedQueryResult = T extends {\n initialData?: infer TInitialData\n}\n ? unknown extends TInitialData\n ? UseQueryResult\n : TInitialData extends TData\n ? DefinedUseQueryResult\n : TInitialData extends () => infer TInitialDataResult\n ? unknown extends TInitialDataResult\n ? UseQueryResult\n : TInitialDataResult extends TData\n ? DefinedUseQueryResult\n : UseQueryResult\n : UseQueryResult\n : UseQueryResult\n\ntype GetUseQueryResult =\n // Part 1: responsible for mapping explicit type parameter to function result, if object\n T extends { queryFnData: any; error?: infer TError; data: infer TData }\n ? GetDefinedOrUndefinedQueryResult\n : T extends { queryFnData: infer TQueryFnData; error?: infer TError }\n ? GetDefinedOrUndefinedQueryResult\n : T extends { data: infer TData; error?: infer TError }\n ? GetDefinedOrUndefinedQueryResult\n : // Part 2: responsible for mapping explicit type parameter to function result, if tuple\n T extends [any, infer TError, infer TData]\n ? GetDefinedOrUndefinedQueryResult\n : T extends [infer TQueryFnData, infer TError]\n ? GetDefinedOrUndefinedQueryResult\n : T extends [infer TQueryFnData]\n ? GetDefinedOrUndefinedQueryResult\n : // Part 3: responsible for mapping inferred type to results, if no explicit parameter was provided\n T extends {\n queryFn?:\n | QueryFunction\n | SkipTokenForUseQueries\n select?: (data: any) => infer TData\n throwOnError?: ThrowOnError\n }\n ? GetDefinedOrUndefinedQueryResult<\n T,\n unknown extends TData ? TQueryFnData : TData,\n unknown extends TError ? DefaultError : TError\n >\n : // Fallback\n UseQueryResult\n\n/**\n * QueriesOptions reducer recursively unwraps function arguments to infer/enforce type param\n */\nexport type QueriesOptions<\n T extends Array,\n TResults extends Array = [],\n TDepth extends ReadonlyArray = [],\n> = TDepth['length'] extends MAXIMUM_DEPTH\n ? Array\n : T extends []\n ? []\n : T extends [infer Head]\n ? [...TResults, GetUseQueryOptionsForUseQueries]\n : T extends [infer Head, ...infer Tails]\n ? QueriesOptions<\n [...Tails],\n [...TResults, GetUseQueryOptionsForUseQueries],\n [...TDepth, 1]\n >\n : ReadonlyArray extends T\n ? T\n : // If T is *some* array but we couldn't assign unknown[] to it, then it must hold some known/homogenous type!\n // use this to infer the param types in the case of Array.map() argument\n T extends Array<\n UseQueryOptionsForUseQueries<\n infer TQueryFnData,\n infer TError,\n infer TData,\n infer TQueryKey\n >\n >\n ? Array<\n UseQueryOptionsForUseQueries<\n TQueryFnData,\n TError,\n TData,\n TQueryKey\n >\n >\n : // Fallback\n Array\n\n/**\n * QueriesResults reducer recursively maps type param to results\n */\nexport type QueriesResults<\n T extends Array,\n TResults extends Array = [],\n TDepth extends ReadonlyArray = [],\n> = TDepth['length'] extends MAXIMUM_DEPTH\n ? Array\n : T extends []\n ? []\n : T extends [infer Head]\n ? [...TResults, GetUseQueryResult]\n : T extends [infer Head, ...infer Tails]\n ? QueriesResults<\n [...Tails],\n [...TResults, GetUseQueryResult],\n [...TDepth, 1]\n >\n : T extends Array<\n UseQueryOptionsForUseQueries<\n infer TQueryFnData,\n infer TError,\n infer TData,\n any\n >\n >\n ? // Dynamic-size (homogenous) UseQueryOptions array: map directly to array of results\n Array<\n UseQueryResult<\n unknown extends TData ? TQueryFnData : TData,\n unknown extends TError ? DefaultError : TError\n >\n >\n : // Fallback\n Array\n\nexport function useQueries<\n T extends Array,\n TCombinedResult = QueriesResults,\n>(\n {\n queries,\n ...options\n }: {\n queries: readonly [...QueriesOptions]\n combine?: (result: QueriesResults) => TCombinedResult\n },\n queryClient?: QueryClient,\n): TCombinedResult {\n const client = useQueryClient(queryClient)\n const isRestoring = useIsRestoring()\n const errorResetBoundary = useQueryErrorResetBoundary()\n\n const defaultedQueries = React.useMemo(\n () =>\n queries.map((opts) => {\n const defaultedOptions = client.defaultQueryOptions(\n opts as QueryObserverOptions,\n )\n\n // Make sure the results are already in fetching state before subscribing or updating options\n defaultedOptions._optimisticResults = isRestoring\n ? 'isRestoring'\n : 'optimistic'\n\n return defaultedOptions\n }),\n [queries, client, isRestoring],\n )\n\n defaultedQueries.forEach((query) => {\n ensureSuspenseTimers(query)\n ensurePreventErrorBoundaryRetry(query, errorResetBoundary)\n })\n\n useClearResetErrorBoundary(errorResetBoundary)\n\n const [observer] = React.useState(\n () =>\n new QueriesObserver(\n client,\n defaultedQueries,\n options as QueriesObserverOptions,\n ),\n )\n\n const [optimisticResult, getCombinedResult, trackResult] =\n observer.getOptimisticResult(\n defaultedQueries,\n (options as QueriesObserverOptions).combine,\n )\n\n useSyncExternalStore(\n React.useCallback(\n (onStoreChange) =>\n isRestoring\n ? noop\n : observer.subscribe(notifyManager.batchCalls(onStoreChange)),\n [observer, isRestoring],\n ),\n () => observer.getCurrentResult(),\n () => observer.getCurrentResult(),\n )\n\n React.useEffect(() => {\n // Do not notify on updates because of changes in the options because\n // these changes should already be reflected in the optimistic result.\n observer.setQueries(\n defaultedQueries,\n options as QueriesObserverOptions,\n {\n listeners: false,\n },\n )\n }, [defaultedQueries, options, observer])\n\n const shouldAtLeastOneSuspend = optimisticResult.some((result, index) =>\n shouldSuspend(defaultedQueries[index], result),\n )\n\n const suspensePromises = shouldAtLeastOneSuspend\n ? optimisticResult.flatMap((result, index) => {\n const opts = defaultedQueries[index]\n\n if (opts) {\n const queryObserver = new QueryObserver(client, opts)\n if (shouldSuspend(opts, result)) {\n return fetchOptimistic(opts, queryObserver, errorResetBoundary)\n } else if (willFetch(result, isRestoring)) {\n void fetchOptimistic(opts, queryObserver, errorResetBoundary)\n }\n }\n return []\n })\n : []\n\n if (suspensePromises.length > 0) {\n throw Promise.all(suspensePromises)\n }\n const firstSingleResultWhichShouldThrow = optimisticResult.find(\n (result, index) => {\n const query = defaultedQueries[index]\n return (\n query &&\n getHasError({\n result,\n errorResetBoundary,\n throwOnError: query.throwOnError,\n query: client.getQueryCache().get(query.queryHash),\n })\n )\n },\n )\n\n if (firstSingleResultWhichShouldThrow?.error) {\n throw firstSingleResultWhichShouldThrow.error\n }\n\n return getCombinedResult(trackResult())\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AACA,YAAuB;AACvB,kBAAqC;AAErC,wBAIO;AACP,iCAA+B;AAC/B,yBAA+B;AAC/B,qCAA2C;AAC3C,gCAIO;AACP,sBAKO;AACP,mBAAqB;AAyMd,SAAS,WAId;AAAA,EACE;AAAA,EACA,GAAG;AACL,GAIA,aACiB;AACjB,QAAM,aAAS,2CAAe,WAAW;AACzC,QAAM,kBAAc,mCAAe;AACnC,QAAM,yBAAqB,2DAA2B;AAEtD,QAAM,mBAAyB;AAAA,IAC7B,MACE,QAAQ,IAAI,CAAC,SAAS;AACpB,YAAM,mBAAmB,OAAO;AAAA,QAC9B;AAAA,MACF;AAGA,uBAAiB,qBAAqB,cAClC,gBACA;AAEJ,aAAO;AAAA,IACT,CAAC;AAAA,IACH,CAAC,SAAS,QAAQ,WAAW;AAAA,EAC/B;AAEA,mBAAiB,QAAQ,CAAC,UAAU;AAClC,8CAAqB,KAAK;AAC1B,mEAAgC,OAAO,kBAAkB;AAAA,EAC3D,CAAC;AAED,4DAA2B,kBAAkB;AAE7C,QAAM,CAAC,QAAQ,IAAU;AAAA,IACvB,MACE,IAAI;AAAA,MACF;AAAA,MACA;AAAA,MACA;AAAA,IACF;AAAA,EACJ;AAEA,QAAM,CAAC,kBAAkB,mBAAmB,WAAW,IACrD,SAAS;AAAA,IACP;AAAA,IACC,QAAoD;AAAA,EACvD;AAEF;AAAA,IACQ;AAAA,MACJ,CAAC,kBACC,cACI,oBACA,SAAS,UAAU,gCAAc,WAAW,aAAa,CAAC;AAAA,MAChE,CAAC,UAAU,WAAW;AAAA,IACxB;AAAA,IACA,MAAM,SAAS,iBAAiB;AAAA,IAChC,MAAM,SAAS,iBAAiB;AAAA,EAClC;AAEA,EAAM,gBAAU,MAAM;AAGpB,aAAS;AAAA,MACP;AAAA,MACA;AAAA,MACA;AAAA,QACE,WAAW;AAAA,MACb;AAAA,IACF;AAAA,EACF,GAAG,CAAC,kBAAkB,SAAS,QAAQ,CAAC;AAExC,QAAM,0BAA0B,iBAAiB;AAAA,IAAK,CAAC,QAAQ,cAC7D,+BAAc,iBAAiB,KAAK,GAAG,MAAM;AAAA,EAC/C;AAEA,QAAM,mBAAmB,0BACrB,iBAAiB,QAAQ,CAAC,QAAQ,UAAU;AAC1C,UAAM,OAAO,iBAAiB,KAAK;AAEnC,QAAI,MAAM;AACR,YAAM,gBAAgB,IAAI,gCAAc,QAAQ,IAAI;AACpD,cAAI,+BAAc,MAAM,MAAM,GAAG;AAC/B,mBAAO,iCAAgB,MAAM,eAAe,kBAAkB;AAAA,MAChE,eAAW,2BAAU,QAAQ,WAAW,GAAG;AACzC,iBAAK,iCAAgB,MAAM,eAAe,kBAAkB;AAAA,MAC9D;AAAA,IACF;AACA,WAAO,CAAC;AAAA,EACV,CAAC,IACD,CAAC;AAEL,MAAI,iBAAiB,SAAS,GAAG;AAC/B,UAAM,QAAQ,IAAI,gBAAgB;AAAA,EACpC;AACA,QAAM,oCAAoC,iBAAiB;AAAA,IACzD,CAAC,QAAQ,UAAU;AACjB,YAAM,QAAQ,iBAAiB,KAAK;AACpC,aACE,aACA,uCAAY;AAAA,QACV;AAAA,QACA;AAAA,QACA,cAAc,MAAM;AAAA,QACpB,OAAO,OAAO,cAAc,EAAE,IAAI,MAAM,SAAS;AAAA,MACnD,CAAC;AAAA,IAEL;AAAA,EACF;AAEA,MAAI,mCAAmC,OAAO;AAC5C,UAAM,kCAAkC;AAAA,EAC1C;AAEA,SAAO,kBAAkB,YAAY,CAAC;AACxC;","names":[]} +\ No newline at end of file +diff --git a/build/modern/useQueries.js b/build/modern/useQueries.js +index c09facb7f2f05a71a62c8543e4d9bf08ff18d718..52ba2a55518517b0b0d1d40a5a2dbb038ddc19e5 100644 +--- a/build/modern/useQueries.js ++++ b/build/modern/useQueries.js +@@ -2,6 +2,7 @@ + + // src/useQueries.ts + import * as React from "react"; ++import { useSyncExternalStore } from "use-sync-external-store/shim/index.js"; + import { + QueriesObserver, + QueryObserver, +@@ -55,7 +56,7 @@ function useQueries({ + defaultedQueries, + options.combine + ); +- React.useSyncExternalStore( ++ useSyncExternalStore( + React.useCallback( + (onStoreChange) => isRestoring ? noop : observer.subscribe(notifyManager.batchCalls(onStoreChange)), + [observer, isRestoring] +diff --git a/build/modern/useQueries.js.map b/build/modern/useQueries.js.map +index cce8620de6f08dc7b6dd927df034edc54ab0ea50..a4c9aad6ffdf06c8946073559447bae8e63d4761 100644 +--- a/build/modern/useQueries.js.map ++++ b/build/modern/useQueries.js.map +@@ -1 +1 @@ +-{"version":3,"sources":["../../src/useQueries.ts"],"sourcesContent":["'use client'\nimport * as React from 'react'\n\nimport {\n QueriesObserver,\n QueryObserver,\n notifyManager,\n} from '@tanstack/query-core'\nimport { useQueryClient } from './QueryClientProvider'\nimport { useIsRestoring } from './isRestoring'\nimport { useQueryErrorResetBoundary } from './QueryErrorResetBoundary'\nimport {\n ensurePreventErrorBoundaryRetry,\n getHasError,\n useClearResetErrorBoundary,\n} from './errorBoundaryUtils'\nimport {\n ensureSuspenseTimers,\n fetchOptimistic,\n shouldSuspend,\n willFetch,\n} from './suspense'\nimport { noop } from './utils'\nimport type {\n DefinedUseQueryResult,\n UseQueryOptions,\n UseQueryResult,\n} from './types'\nimport type {\n DefaultError,\n OmitKeyof,\n QueriesObserverOptions,\n QueriesPlaceholderDataFunction,\n QueryClient,\n QueryFunction,\n QueryKey,\n QueryObserverOptions,\n ThrowOnError,\n} from '@tanstack/query-core'\n\n// This defines the `UseQueryOptions` that are accepted in `QueriesOptions` & `GetOptions`.\n// `placeholderData` function always gets undefined passed\ntype UseQueryOptionsForUseQueries<\n TQueryFnData = unknown,\n TError = DefaultError,\n TData = TQueryFnData,\n TQueryKey extends QueryKey = QueryKey,\n> = OmitKeyof<\n UseQueryOptions,\n 'placeholderData'\n> & {\n placeholderData?: TQueryFnData | QueriesPlaceholderDataFunction\n}\n\n// Avoid TS depth-limit error in case of large array literal\ntype MAXIMUM_DEPTH = 20\n\n// Widen the type of the symbol to enable type inference even if skipToken is not immutable.\ntype SkipTokenForUseQueries = symbol\n\ntype GetUseQueryOptionsForUseQueries =\n // Part 1: responsible for applying explicit type parameter to function arguments, if object { queryFnData: TQueryFnData, error: TError, data: TData }\n T extends {\n queryFnData: infer TQueryFnData\n error?: infer TError\n data: infer TData\n }\n ? UseQueryOptionsForUseQueries\n : T extends { queryFnData: infer TQueryFnData; error?: infer TError }\n ? UseQueryOptionsForUseQueries\n : T extends { data: infer TData; error?: infer TError }\n ? UseQueryOptionsForUseQueries\n : // Part 2: responsible for applying explicit type parameter to function arguments, if tuple [TQueryFnData, TError, TData]\n T extends [infer TQueryFnData, infer TError, infer TData]\n ? UseQueryOptionsForUseQueries\n : T extends [infer TQueryFnData, infer TError]\n ? UseQueryOptionsForUseQueries\n : T extends [infer TQueryFnData]\n ? UseQueryOptionsForUseQueries\n : // Part 3: responsible for inferring and enforcing type if no explicit parameter was provided\n T extends {\n queryFn?:\n | QueryFunction\n | SkipTokenForUseQueries\n select?: (data: any) => infer TData\n throwOnError?: ThrowOnError\n }\n ? UseQueryOptionsForUseQueries<\n TQueryFnData,\n unknown extends TError ? DefaultError : TError,\n unknown extends TData ? TQueryFnData : TData,\n TQueryKey\n >\n : // Fallback\n UseQueryOptionsForUseQueries\n\n// A defined initialData setting should return a DefinedUseQueryResult rather than UseQueryResult\ntype GetDefinedOrUndefinedQueryResult = T extends {\n initialData?: infer TInitialData\n}\n ? unknown extends TInitialData\n ? UseQueryResult\n : TInitialData extends TData\n ? DefinedUseQueryResult\n : TInitialData extends () => infer TInitialDataResult\n ? unknown extends TInitialDataResult\n ? UseQueryResult\n : TInitialDataResult extends TData\n ? DefinedUseQueryResult\n : UseQueryResult\n : UseQueryResult\n : UseQueryResult\n\ntype GetUseQueryResult =\n // Part 1: responsible for mapping explicit type parameter to function result, if object\n T extends { queryFnData: any; error?: infer TError; data: infer TData }\n ? GetDefinedOrUndefinedQueryResult\n : T extends { queryFnData: infer TQueryFnData; error?: infer TError }\n ? GetDefinedOrUndefinedQueryResult\n : T extends { data: infer TData; error?: infer TError }\n ? GetDefinedOrUndefinedQueryResult\n : // Part 2: responsible for mapping explicit type parameter to function result, if tuple\n T extends [any, infer TError, infer TData]\n ? GetDefinedOrUndefinedQueryResult\n : T extends [infer TQueryFnData, infer TError]\n ? GetDefinedOrUndefinedQueryResult\n : T extends [infer TQueryFnData]\n ? GetDefinedOrUndefinedQueryResult\n : // Part 3: responsible for mapping inferred type to results, if no explicit parameter was provided\n T extends {\n queryFn?:\n | QueryFunction\n | SkipTokenForUseQueries\n select?: (data: any) => infer TData\n throwOnError?: ThrowOnError\n }\n ? GetDefinedOrUndefinedQueryResult<\n T,\n unknown extends TData ? TQueryFnData : TData,\n unknown extends TError ? DefaultError : TError\n >\n : // Fallback\n UseQueryResult\n\n/**\n * QueriesOptions reducer recursively unwraps function arguments to infer/enforce type param\n */\nexport type QueriesOptions<\n T extends Array,\n TResults extends Array = [],\n TDepth extends ReadonlyArray = [],\n> = TDepth['length'] extends MAXIMUM_DEPTH\n ? Array\n : T extends []\n ? []\n : T extends [infer Head]\n ? [...TResults, GetUseQueryOptionsForUseQueries]\n : T extends [infer Head, ...infer Tails]\n ? QueriesOptions<\n [...Tails],\n [...TResults, GetUseQueryOptionsForUseQueries],\n [...TDepth, 1]\n >\n : ReadonlyArray extends T\n ? T\n : // If T is *some* array but we couldn't assign unknown[] to it, then it must hold some known/homogenous type!\n // use this to infer the param types in the case of Array.map() argument\n T extends Array<\n UseQueryOptionsForUseQueries<\n infer TQueryFnData,\n infer TError,\n infer TData,\n infer TQueryKey\n >\n >\n ? Array<\n UseQueryOptionsForUseQueries<\n TQueryFnData,\n TError,\n TData,\n TQueryKey\n >\n >\n : // Fallback\n Array\n\n/**\n * QueriesResults reducer recursively maps type param to results\n */\nexport type QueriesResults<\n T extends Array,\n TResults extends Array = [],\n TDepth extends ReadonlyArray = [],\n> = TDepth['length'] extends MAXIMUM_DEPTH\n ? Array\n : T extends []\n ? []\n : T extends [infer Head]\n ? [...TResults, GetUseQueryResult]\n : T extends [infer Head, ...infer Tails]\n ? QueriesResults<\n [...Tails],\n [...TResults, GetUseQueryResult],\n [...TDepth, 1]\n >\n : T extends Array<\n UseQueryOptionsForUseQueries<\n infer TQueryFnData,\n infer TError,\n infer TData,\n any\n >\n >\n ? // Dynamic-size (homogenous) UseQueryOptions array: map directly to array of results\n Array<\n UseQueryResult<\n unknown extends TData ? TQueryFnData : TData,\n unknown extends TError ? DefaultError : TError\n >\n >\n : // Fallback\n Array\n\nexport function useQueries<\n T extends Array,\n TCombinedResult = QueriesResults,\n>(\n {\n queries,\n ...options\n }: {\n queries: readonly [...QueriesOptions]\n combine?: (result: QueriesResults) => TCombinedResult\n },\n queryClient?: QueryClient,\n): TCombinedResult {\n const client = useQueryClient(queryClient)\n const isRestoring = useIsRestoring()\n const errorResetBoundary = useQueryErrorResetBoundary()\n\n const defaultedQueries = React.useMemo(\n () =>\n queries.map((opts) => {\n const defaultedOptions = client.defaultQueryOptions(\n opts as QueryObserverOptions,\n )\n\n // Make sure the results are already in fetching state before subscribing or updating options\n defaultedOptions._optimisticResults = isRestoring\n ? 'isRestoring'\n : 'optimistic'\n\n return defaultedOptions\n }),\n [queries, client, isRestoring],\n )\n\n defaultedQueries.forEach((query) => {\n ensureSuspenseTimers(query)\n ensurePreventErrorBoundaryRetry(query, errorResetBoundary)\n })\n\n useClearResetErrorBoundary(errorResetBoundary)\n\n const [observer] = React.useState(\n () =>\n new QueriesObserver(\n client,\n defaultedQueries,\n options as QueriesObserverOptions,\n ),\n )\n\n const [optimisticResult, getCombinedResult, trackResult] =\n observer.getOptimisticResult(\n defaultedQueries,\n (options as QueriesObserverOptions).combine,\n )\n\n React.useSyncExternalStore(\n React.useCallback(\n (onStoreChange) =>\n isRestoring\n ? noop\n : observer.subscribe(notifyManager.batchCalls(onStoreChange)),\n [observer, isRestoring],\n ),\n () => observer.getCurrentResult(),\n () => observer.getCurrentResult(),\n )\n\n React.useEffect(() => {\n // Do not notify on updates because of changes in the options because\n // these changes should already be reflected in the optimistic result.\n observer.setQueries(\n defaultedQueries,\n options as QueriesObserverOptions,\n {\n listeners: false,\n },\n )\n }, [defaultedQueries, options, observer])\n\n const shouldAtLeastOneSuspend = optimisticResult.some((result, index) =>\n shouldSuspend(defaultedQueries[index], result),\n )\n\n const suspensePromises = shouldAtLeastOneSuspend\n ? optimisticResult.flatMap((result, index) => {\n const opts = defaultedQueries[index]\n\n if (opts) {\n const queryObserver = new QueryObserver(client, opts)\n if (shouldSuspend(opts, result)) {\n return fetchOptimistic(opts, queryObserver, errorResetBoundary)\n } else if (willFetch(result, isRestoring)) {\n void fetchOptimistic(opts, queryObserver, errorResetBoundary)\n }\n }\n return []\n })\n : []\n\n if (suspensePromises.length > 0) {\n throw Promise.all(suspensePromises)\n }\n const firstSingleResultWhichShouldThrow = optimisticResult.find(\n (result, index) => {\n const query = defaultedQueries[index]\n return (\n query &&\n getHasError({\n result,\n errorResetBoundary,\n throwOnError: query.throwOnError,\n query: client.getQueryCache().get(query.queryHash),\n })\n )\n },\n )\n\n if (firstSingleResultWhichShouldThrow?.error) {\n throw firstSingleResultWhichShouldThrow.error\n }\n\n return getCombinedResult(trackResult())\n}\n"],"mappings":";;;AACA,YAAY,WAAW;AAEvB;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,OACK;AACP,SAAS,sBAAsB;AAC/B,SAAS,sBAAsB;AAC/B,SAAS,kCAAkC;AAC3C;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,OACK;AACP;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OACK;AACP,SAAS,YAAY;AAyMd,SAAS,WAId;AAAA,EACE;AAAA,EACA,GAAG;AACL,GAIA,aACiB;AACjB,QAAM,SAAS,eAAe,WAAW;AACzC,QAAM,cAAc,eAAe;AACnC,QAAM,qBAAqB,2BAA2B;AAEtD,QAAM,mBAAyB;AAAA,IAC7B,MACE,QAAQ,IAAI,CAAC,SAAS;AACpB,YAAM,mBAAmB,OAAO;AAAA,QAC9B;AAAA,MACF;AAGA,uBAAiB,qBAAqB,cAClC,gBACA;AAEJ,aAAO;AAAA,IACT,CAAC;AAAA,IACH,CAAC,SAAS,QAAQ,WAAW;AAAA,EAC/B;AAEA,mBAAiB,QAAQ,CAAC,UAAU;AAClC,yBAAqB,KAAK;AAC1B,oCAAgC,OAAO,kBAAkB;AAAA,EAC3D,CAAC;AAED,6BAA2B,kBAAkB;AAE7C,QAAM,CAAC,QAAQ,IAAU;AAAA,IACvB,MACE,IAAI;AAAA,MACF;AAAA,MACA;AAAA,MACA;AAAA,IACF;AAAA,EACJ;AAEA,QAAM,CAAC,kBAAkB,mBAAmB,WAAW,IACrD,SAAS;AAAA,IACP;AAAA,IACC,QAAoD;AAAA,EACvD;AAEF,EAAM;AAAA,IACE;AAAA,MACJ,CAAC,kBACC,cACI,OACA,SAAS,UAAU,cAAc,WAAW,aAAa,CAAC;AAAA,MAChE,CAAC,UAAU,WAAW;AAAA,IACxB;AAAA,IACA,MAAM,SAAS,iBAAiB;AAAA,IAChC,MAAM,SAAS,iBAAiB;AAAA,EAClC;AAEA,EAAM,gBAAU,MAAM;AAGpB,aAAS;AAAA,MACP;AAAA,MACA;AAAA,MACA;AAAA,QACE,WAAW;AAAA,MACb;AAAA,IACF;AAAA,EACF,GAAG,CAAC,kBAAkB,SAAS,QAAQ,CAAC;AAExC,QAAM,0BAA0B,iBAAiB;AAAA,IAAK,CAAC,QAAQ,UAC7D,cAAc,iBAAiB,KAAK,GAAG,MAAM;AAAA,EAC/C;AAEA,QAAM,mBAAmB,0BACrB,iBAAiB,QAAQ,CAAC,QAAQ,UAAU;AAC1C,UAAM,OAAO,iBAAiB,KAAK;AAEnC,QAAI,MAAM;AACR,YAAM,gBAAgB,IAAI,cAAc,QAAQ,IAAI;AACpD,UAAI,cAAc,MAAM,MAAM,GAAG;AAC/B,eAAO,gBAAgB,MAAM,eAAe,kBAAkB;AAAA,MAChE,WAAW,UAAU,QAAQ,WAAW,GAAG;AACzC,aAAK,gBAAgB,MAAM,eAAe,kBAAkB;AAAA,MAC9D;AAAA,IACF;AACA,WAAO,CAAC;AAAA,EACV,CAAC,IACD,CAAC;AAEL,MAAI,iBAAiB,SAAS,GAAG;AAC/B,UAAM,QAAQ,IAAI,gBAAgB;AAAA,EACpC;AACA,QAAM,oCAAoC,iBAAiB;AAAA,IACzD,CAAC,QAAQ,UAAU;AACjB,YAAM,QAAQ,iBAAiB,KAAK;AACpC,aACE,SACA,YAAY;AAAA,QACV;AAAA,QACA;AAAA,QACA,cAAc,MAAM;AAAA,QACpB,OAAO,OAAO,cAAc,EAAE,IAAI,MAAM,SAAS;AAAA,MACnD,CAAC;AAAA,IAEL;AAAA,EACF;AAEA,MAAI,mCAAmC,OAAO;AAC5C,UAAM,kCAAkC;AAAA,EAC1C;AAEA,SAAO,kBAAkB,YAAY,CAAC;AACxC;","names":[]} +\ No newline at end of file ++{"version":3,"sources":["../../src/useQueries.ts"],"sourcesContent":["'use client'\nimport * as React from 'react'\nimport { useSyncExternalStore } from 'use-sync-external-store/shim/index.js'\n\nimport {\n QueriesObserver,\n QueryObserver,\n notifyManager,\n} from '@tanstack/query-core'\nimport { useQueryClient } from './QueryClientProvider'\nimport { useIsRestoring } from './isRestoring'\nimport { useQueryErrorResetBoundary } from './QueryErrorResetBoundary'\nimport {\n ensurePreventErrorBoundaryRetry,\n getHasError,\n useClearResetErrorBoundary,\n} from './errorBoundaryUtils'\nimport {\n ensureSuspenseTimers,\n fetchOptimistic,\n shouldSuspend,\n willFetch,\n} from './suspense'\nimport { noop } from './utils'\nimport type {\n DefinedUseQueryResult,\n UseQueryOptions,\n UseQueryResult,\n} from './types'\nimport type {\n DefaultError,\n OmitKeyof,\n QueriesObserverOptions,\n QueriesPlaceholderDataFunction,\n QueryClient,\n QueryFunction,\n QueryKey,\n QueryObserverOptions,\n ThrowOnError,\n} from '@tanstack/query-core'\n\n// This defines the `UseQueryOptions` that are accepted in `QueriesOptions` & `GetOptions`.\n// `placeholderData` function always gets undefined passed\ntype UseQueryOptionsForUseQueries<\n TQueryFnData = unknown,\n TError = DefaultError,\n TData = TQueryFnData,\n TQueryKey extends QueryKey = QueryKey,\n> = OmitKeyof<\n UseQueryOptions,\n 'placeholderData'\n> & {\n placeholderData?: TQueryFnData | QueriesPlaceholderDataFunction\n}\n\n// Avoid TS depth-limit error in case of large array literal\ntype MAXIMUM_DEPTH = 20\n\n// Widen the type of the symbol to enable type inference even if skipToken is not immutable.\ntype SkipTokenForUseQueries = symbol\n\ntype GetUseQueryOptionsForUseQueries =\n // Part 1: responsible for applying explicit type parameter to function arguments, if object { queryFnData: TQueryFnData, error: TError, data: TData }\n T extends {\n queryFnData: infer TQueryFnData\n error?: infer TError\n data: infer TData\n }\n ? UseQueryOptionsForUseQueries\n : T extends { queryFnData: infer TQueryFnData; error?: infer TError }\n ? UseQueryOptionsForUseQueries\n : T extends { data: infer TData; error?: infer TError }\n ? UseQueryOptionsForUseQueries\n : // Part 2: responsible for applying explicit type parameter to function arguments, if tuple [TQueryFnData, TError, TData]\n T extends [infer TQueryFnData, infer TError, infer TData]\n ? UseQueryOptionsForUseQueries\n : T extends [infer TQueryFnData, infer TError]\n ? UseQueryOptionsForUseQueries\n : T extends [infer TQueryFnData]\n ? UseQueryOptionsForUseQueries\n : // Part 3: responsible for inferring and enforcing type if no explicit parameter was provided\n T extends {\n queryFn?:\n | QueryFunction\n | SkipTokenForUseQueries\n select?: (data: any) => infer TData\n throwOnError?: ThrowOnError\n }\n ? UseQueryOptionsForUseQueries<\n TQueryFnData,\n unknown extends TError ? DefaultError : TError,\n unknown extends TData ? TQueryFnData : TData,\n TQueryKey\n >\n : // Fallback\n UseQueryOptionsForUseQueries\n\n// A defined initialData setting should return a DefinedUseQueryResult rather than UseQueryResult\ntype GetDefinedOrUndefinedQueryResult = T extends {\n initialData?: infer TInitialData\n}\n ? unknown extends TInitialData\n ? UseQueryResult\n : TInitialData extends TData\n ? DefinedUseQueryResult\n : TInitialData extends () => infer TInitialDataResult\n ? unknown extends TInitialDataResult\n ? UseQueryResult\n : TInitialDataResult extends TData\n ? DefinedUseQueryResult\n : UseQueryResult\n : UseQueryResult\n : UseQueryResult\n\ntype GetUseQueryResult =\n // Part 1: responsible for mapping explicit type parameter to function result, if object\n T extends { queryFnData: any; error?: infer TError; data: infer TData }\n ? GetDefinedOrUndefinedQueryResult\n : T extends { queryFnData: infer TQueryFnData; error?: infer TError }\n ? GetDefinedOrUndefinedQueryResult\n : T extends { data: infer TData; error?: infer TError }\n ? GetDefinedOrUndefinedQueryResult\n : // Part 2: responsible for mapping explicit type parameter to function result, if tuple\n T extends [any, infer TError, infer TData]\n ? GetDefinedOrUndefinedQueryResult\n : T extends [infer TQueryFnData, infer TError]\n ? GetDefinedOrUndefinedQueryResult\n : T extends [infer TQueryFnData]\n ? GetDefinedOrUndefinedQueryResult\n : // Part 3: responsible for mapping inferred type to results, if no explicit parameter was provided\n T extends {\n queryFn?:\n | QueryFunction\n | SkipTokenForUseQueries\n select?: (data: any) => infer TData\n throwOnError?: ThrowOnError\n }\n ? GetDefinedOrUndefinedQueryResult<\n T,\n unknown extends TData ? TQueryFnData : TData,\n unknown extends TError ? DefaultError : TError\n >\n : // Fallback\n UseQueryResult\n\n/**\n * QueriesOptions reducer recursively unwraps function arguments to infer/enforce type param\n */\nexport type QueriesOptions<\n T extends Array,\n TResults extends Array = [],\n TDepth extends ReadonlyArray = [],\n> = TDepth['length'] extends MAXIMUM_DEPTH\n ? Array\n : T extends []\n ? []\n : T extends [infer Head]\n ? [...TResults, GetUseQueryOptionsForUseQueries]\n : T extends [infer Head, ...infer Tails]\n ? QueriesOptions<\n [...Tails],\n [...TResults, GetUseQueryOptionsForUseQueries],\n [...TDepth, 1]\n >\n : ReadonlyArray extends T\n ? T\n : // If T is *some* array but we couldn't assign unknown[] to it, then it must hold some known/homogenous type!\n // use this to infer the param types in the case of Array.map() argument\n T extends Array<\n UseQueryOptionsForUseQueries<\n infer TQueryFnData,\n infer TError,\n infer TData,\n infer TQueryKey\n >\n >\n ? Array<\n UseQueryOptionsForUseQueries<\n TQueryFnData,\n TError,\n TData,\n TQueryKey\n >\n >\n : // Fallback\n Array\n\n/**\n * QueriesResults reducer recursively maps type param to results\n */\nexport type QueriesResults<\n T extends Array,\n TResults extends Array = [],\n TDepth extends ReadonlyArray = [],\n> = TDepth['length'] extends MAXIMUM_DEPTH\n ? Array\n : T extends []\n ? []\n : T extends [infer Head]\n ? [...TResults, GetUseQueryResult]\n : T extends [infer Head, ...infer Tails]\n ? QueriesResults<\n [...Tails],\n [...TResults, GetUseQueryResult],\n [...TDepth, 1]\n >\n : T extends Array<\n UseQueryOptionsForUseQueries<\n infer TQueryFnData,\n infer TError,\n infer TData,\n any\n >\n >\n ? // Dynamic-size (homogenous) UseQueryOptions array: map directly to array of results\n Array<\n UseQueryResult<\n unknown extends TData ? TQueryFnData : TData,\n unknown extends TError ? DefaultError : TError\n >\n >\n : // Fallback\n Array\n\nexport function useQueries<\n T extends Array,\n TCombinedResult = QueriesResults,\n>(\n {\n queries,\n ...options\n }: {\n queries: readonly [...QueriesOptions]\n combine?: (result: QueriesResults) => TCombinedResult\n },\n queryClient?: QueryClient,\n): TCombinedResult {\n const client = useQueryClient(queryClient)\n const isRestoring = useIsRestoring()\n const errorResetBoundary = useQueryErrorResetBoundary()\n\n const defaultedQueries = React.useMemo(\n () =>\n queries.map((opts) => {\n const defaultedOptions = client.defaultQueryOptions(\n opts as QueryObserverOptions,\n )\n\n // Make sure the results are already in fetching state before subscribing or updating options\n defaultedOptions._optimisticResults = isRestoring\n ? 'isRestoring'\n : 'optimistic'\n\n return defaultedOptions\n }),\n [queries, client, isRestoring],\n )\n\n defaultedQueries.forEach((query) => {\n ensureSuspenseTimers(query)\n ensurePreventErrorBoundaryRetry(query, errorResetBoundary)\n })\n\n useClearResetErrorBoundary(errorResetBoundary)\n\n const [observer] = React.useState(\n () =>\n new QueriesObserver(\n client,\n defaultedQueries,\n options as QueriesObserverOptions,\n ),\n )\n\n const [optimisticResult, getCombinedResult, trackResult] =\n observer.getOptimisticResult(\n defaultedQueries,\n (options as QueriesObserverOptions).combine,\n )\n\n useSyncExternalStore(\n React.useCallback(\n (onStoreChange) =>\n isRestoring\n ? noop\n : observer.subscribe(notifyManager.batchCalls(onStoreChange)),\n [observer, isRestoring],\n ),\n () => observer.getCurrentResult(),\n () => observer.getCurrentResult(),\n )\n\n React.useEffect(() => {\n // Do not notify on updates because of changes in the options because\n // these changes should already be reflected in the optimistic result.\n observer.setQueries(\n defaultedQueries,\n options as QueriesObserverOptions,\n {\n listeners: false,\n },\n )\n }, [defaultedQueries, options, observer])\n\n const shouldAtLeastOneSuspend = optimisticResult.some((result, index) =>\n shouldSuspend(defaultedQueries[index], result),\n )\n\n const suspensePromises = shouldAtLeastOneSuspend\n ? optimisticResult.flatMap((result, index) => {\n const opts = defaultedQueries[index]\n\n if (opts) {\n const queryObserver = new QueryObserver(client, opts)\n if (shouldSuspend(opts, result)) {\n return fetchOptimistic(opts, queryObserver, errorResetBoundary)\n } else if (willFetch(result, isRestoring)) {\n void fetchOptimistic(opts, queryObserver, errorResetBoundary)\n }\n }\n return []\n })\n : []\n\n if (suspensePromises.length > 0) {\n throw Promise.all(suspensePromises)\n }\n const firstSingleResultWhichShouldThrow = optimisticResult.find(\n (result, index) => {\n const query = defaultedQueries[index]\n return (\n query &&\n getHasError({\n result,\n errorResetBoundary,\n throwOnError: query.throwOnError,\n query: client.getQueryCache().get(query.queryHash),\n })\n )\n },\n )\n\n if (firstSingleResultWhichShouldThrow?.error) {\n throw firstSingleResultWhichShouldThrow.error\n }\n\n return getCombinedResult(trackResult())\n}\n"],"mappings":";;;AACA,YAAY,WAAW;AACvB,SAAS,4BAA4B;AAErC;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,OACK;AACP,SAAS,sBAAsB;AAC/B,SAAS,sBAAsB;AAC/B,SAAS,kCAAkC;AAC3C;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,OACK;AACP;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OACK;AACP,SAAS,YAAY;AAyMd,SAAS,WAId;AAAA,EACE;AAAA,EACA,GAAG;AACL,GAIA,aACiB;AACjB,QAAM,SAAS,eAAe,WAAW;AACzC,QAAM,cAAc,eAAe;AACnC,QAAM,qBAAqB,2BAA2B;AAEtD,QAAM,mBAAyB;AAAA,IAC7B,MACE,QAAQ,IAAI,CAAC,SAAS;AACpB,YAAM,mBAAmB,OAAO;AAAA,QAC9B;AAAA,MACF;AAGA,uBAAiB,qBAAqB,cAClC,gBACA;AAEJ,aAAO;AAAA,IACT,CAAC;AAAA,IACH,CAAC,SAAS,QAAQ,WAAW;AAAA,EAC/B;AAEA,mBAAiB,QAAQ,CAAC,UAAU;AAClC,yBAAqB,KAAK;AAC1B,oCAAgC,OAAO,kBAAkB;AAAA,EAC3D,CAAC;AAED,6BAA2B,kBAAkB;AAE7C,QAAM,CAAC,QAAQ,IAAU;AAAA,IACvB,MACE,IAAI;AAAA,MACF;AAAA,MACA;AAAA,MACA;AAAA,IACF;AAAA,EACJ;AAEA,QAAM,CAAC,kBAAkB,mBAAmB,WAAW,IACrD,SAAS;AAAA,IACP;AAAA,IACC,QAAoD;AAAA,EACvD;AAEF;AAAA,IACQ;AAAA,MACJ,CAAC,kBACC,cACI,OACA,SAAS,UAAU,cAAc,WAAW,aAAa,CAAC;AAAA,MAChE,CAAC,UAAU,WAAW;AAAA,IACxB;AAAA,IACA,MAAM,SAAS,iBAAiB;AAAA,IAChC,MAAM,SAAS,iBAAiB;AAAA,EAClC;AAEA,EAAM,gBAAU,MAAM;AAGpB,aAAS;AAAA,MACP;AAAA,MACA;AAAA,MACA;AAAA,QACE,WAAW;AAAA,MACb;AAAA,IACF;AAAA,EACF,GAAG,CAAC,kBAAkB,SAAS,QAAQ,CAAC;AAExC,QAAM,0BAA0B,iBAAiB;AAAA,IAAK,CAAC,QAAQ,UAC7D,cAAc,iBAAiB,KAAK,GAAG,MAAM;AAAA,EAC/C;AAEA,QAAM,mBAAmB,0BACrB,iBAAiB,QAAQ,CAAC,QAAQ,UAAU;AAC1C,UAAM,OAAO,iBAAiB,KAAK;AAEnC,QAAI,MAAM;AACR,YAAM,gBAAgB,IAAI,cAAc,QAAQ,IAAI;AACpD,UAAI,cAAc,MAAM,MAAM,GAAG;AAC/B,eAAO,gBAAgB,MAAM,eAAe,kBAAkB;AAAA,MAChE,WAAW,UAAU,QAAQ,WAAW,GAAG;AACzC,aAAK,gBAAgB,MAAM,eAAe,kBAAkB;AAAA,MAC9D;AAAA,IACF;AACA,WAAO,CAAC;AAAA,EACV,CAAC,IACD,CAAC;AAEL,MAAI,iBAAiB,SAAS,GAAG;AAC/B,UAAM,QAAQ,IAAI,gBAAgB;AAAA,EACpC;AACA,QAAM,oCAAoC,iBAAiB;AAAA,IACzD,CAAC,QAAQ,UAAU;AACjB,YAAM,QAAQ,iBAAiB,KAAK;AACpC,aACE,SACA,YAAY;AAAA,QACV;AAAA,QACA;AAAA,QACA,cAAc,MAAM;AAAA,QACpB,OAAO,OAAO,cAAc,EAAE,IAAI,MAAM,SAAS;AAAA,MACnD,CAAC;AAAA,IAEL;AAAA,EACF;AAEA,MAAI,mCAAmC,OAAO;AAC5C,UAAM,kCAAkC;AAAA,EAC1C;AAEA,SAAO,kBAAkB,YAAY,CAAC;AACxC;","names":[]} +\ No newline at end of file +diff --git a/package.json b/package.json +index 822a6ead845585e68f6b6b7942b72718c76cd8d5..cebbaf6792416d47f6aef82d1d1a4a61a8053af7 100644 +--- a/package.json ++++ b/package.json +@@ -47,6 +47,7 @@ + "devDependencies": { + "@types/react": "npm:types-react@rc", + "@types/react-dom": "npm:types-react-dom@rc", ++ "@types/use-sync-external-store": "^0.0.6", + "@vitejs/plugin-react": "^4.3.1", + "eslint-plugin-react-compiler": "0.0.0-experimental-f8a5409-20240829", + "react": "19.0.0-rc-4c2e457c7c-20240522", +diff --git a/src/useBaseQuery.ts b/src/useBaseQuery.ts +index bcbf700ef73cd0b74753b4efa0532de77976d891..6f9ef2e36d13690535d58a1310785300896fe511 100644 +--- a/src/useBaseQuery.ts ++++ b/src/useBaseQuery.ts +@@ -1,5 +1,6 @@ + 'use client' + import * as React from 'react' ++import { useSyncExternalStore } from 'use-sync-external-store/shim/index.js' + + import { isServer, notifyManager } from '@tanstack/query-core' + import { useQueryClient } from './QueryClientProvider' +@@ -84,7 +85,7 @@ export function useBaseQuery< + + const result = observer.getOptimisticResult(defaultedOptions) + +- React.useSyncExternalStore( ++ useSyncExternalStore( + React.useCallback( + (onStoreChange) => { + const unsubscribe = isRestoring +diff --git a/src/useIsFetching.ts b/src/useIsFetching.ts +index a6252912f22e0504e3212bd1aee683b4930db771..5ba06d618eda0a71cbc0d49387e01f035f15863a 100644 +--- a/src/useIsFetching.ts ++++ b/src/useIsFetching.ts +@@ -1,5 +1,7 @@ + 'use client' + import * as React from 'react' ++import { useSyncExternalStore } from 'use-sync-external-store/shim/index.js' ++ + import { notifyManager } from '@tanstack/query-core' + + import { useQueryClient } from './QueryClientProvider' +@@ -12,7 +14,7 @@ export function useIsFetching( + const client = useQueryClient(queryClient) + const queryCache = client.getQueryCache() + +- return React.useSyncExternalStore( ++ return useSyncExternalStore( + React.useCallback( + (onStoreChange) => + queryCache.subscribe(notifyManager.batchCalls(onStoreChange)), +diff --git a/src/useMutation copy.ts b/src/useMutation copy.ts +new file mode 100644 +index 0000000000000000000000000000000000000000..90209500b3d42c53639540fdd9bc0aa47d79b005 +--- /dev/null ++++ b/src/useMutation copy.ts +@@ -0,0 +1,67 @@ ++'use client' ++import * as React from 'react' ++import { useSyncExternalStore } from 'use-sync-external-store/shim/index.js' ++ ++import { MutationObserver, notifyManager } from '@tanstack/query-core' ++import { useQueryClient } from './QueryClientProvider' ++import { noop, shouldThrowError } from './utils' ++import type { ++ UseMutateFunction, ++ UseMutationOptions, ++ UseMutationResult, ++} from './types' ++import type { DefaultError, QueryClient } from '@tanstack/query-core' ++ ++// HOOK ++ ++export function useMutation< ++ TData = unknown, ++ TError = DefaultError, ++ TVariables = void, ++ TContext = unknown, ++>( ++ options: UseMutationOptions, ++ queryClient?: QueryClient, ++): UseMutationResult { ++ const client = useQueryClient(queryClient) ++ ++ const [observer] = React.useState( ++ () => ++ new MutationObserver( ++ client, ++ options, ++ ), ++ ) ++ ++ React.useEffect(() => { ++ observer.setOptions(options) ++ }, [observer, options]) ++ ++ const result = useSyncExternalStore( ++ React.useCallback( ++ (onStoreChange) => ++ observer.subscribe(notifyManager.batchCalls(onStoreChange)), ++ [observer], ++ ), ++ () => observer.getCurrentResult(), ++ () => observer.getCurrentResult(), ++ ) ++ ++ const mutate = React.useCallback< ++ UseMutateFunction ++ >( ++ (variables, mutateOptions) => { ++ observer.mutate(variables, mutateOptions).catch(noop) ++ }, ++ [observer], ++ ) ++ ++ if ( ++ result.error && ++ shouldThrowError(observer.options.throwOnError, [result.error]) ++ ) { ++ throw result.error ++ } ++ ++ return { ...result, mutate, mutateAsync: result.mutate } ++} +diff --git a/src/useMutation.ts b/src/useMutation.ts +deleted file mode 100644 +index 34edd450a2660473396e0c5acd1e3d550c34c43a..0000000000000000000000000000000000000000 +--- a/src/useMutation.ts ++++ /dev/null +@@ -1,65 +0,0 @@ +-'use client' +-import * as React from 'react' +-import { MutationObserver, notifyManager } from '@tanstack/query-core' +-import { useQueryClient } from './QueryClientProvider' +-import { noop, shouldThrowError } from './utils' +-import type { +- UseMutateFunction, +- UseMutationOptions, +- UseMutationResult, +-} from './types' +-import type { DefaultError, QueryClient } from '@tanstack/query-core' +- +-// HOOK +- +-export function useMutation< +- TData = unknown, +- TError = DefaultError, +- TVariables = void, +- TContext = unknown, +->( +- options: UseMutationOptions, +- queryClient?: QueryClient, +-): UseMutationResult { +- const client = useQueryClient(queryClient) +- +- const [observer] = React.useState( +- () => +- new MutationObserver( +- client, +- options, +- ), +- ) +- +- React.useEffect(() => { +- observer.setOptions(options) +- }, [observer, options]) +- +- const result = React.useSyncExternalStore( +- React.useCallback( +- (onStoreChange) => +- observer.subscribe(notifyManager.batchCalls(onStoreChange)), +- [observer], +- ), +- () => observer.getCurrentResult(), +- () => observer.getCurrentResult(), +- ) +- +- const mutate = React.useCallback< +- UseMutateFunction +- >( +- (variables, mutateOptions) => { +- observer.mutate(variables, mutateOptions).catch(noop) +- }, +- [observer], +- ) +- +- if ( +- result.error && +- shouldThrowError(observer.options.throwOnError, [result.error]) +- ) { +- throw result.error +- } +- +- return { ...result, mutate, mutateAsync: result.mutate } +-} +diff --git a/src/useMutationState.ts b/src/useMutationState.ts +index d962bf085d9dc30ba75fcc8fa6dde4e402fa41e7..3834135e17514534ce30bc27121f64b8638f3534 100644 +--- a/src/useMutationState.ts ++++ b/src/useMutationState.ts +@@ -2,6 +2,7 @@ + + 'use client' + import * as React from 'react' ++import { useSyncExternalStore } from 'use-sync-external-store/shim/index.js' + + import { notifyManager, replaceEqualDeep } from '@tanstack/query-core' + import { useQueryClient } from './QueryClientProvider' +@@ -56,7 +57,7 @@ export function useMutationState( + optionsRef.current = options + }) + +- return React.useSyncExternalStore( ++ return useSyncExternalStore( + React.useCallback( + (onStoreChange) => + mutationCache.subscribe(() => { +diff --git a/src/useQueries.ts b/src/useQueries.ts +index 90ef2e32ad0d2267b2f3266cc5dc078ff9786e3f..505ce2e3312c67074a57a460cbda89c145d64de5 100644 +--- a/src/useQueries.ts ++++ b/src/useQueries.ts +@@ -1,5 +1,6 @@ + 'use client' + import * as React from 'react' ++import { useSyncExternalStore } from 'use-sync-external-store/shim/index.js' + + import { + QueriesObserver, +@@ -277,7 +278,7 @@ export function useQueries< + (options as QueriesObserverOptions).combine, + ) + +- React.useSyncExternalStore( ++ useSyncExternalStore( + React.useCallback( + (onStoreChange) => + isRestoring diff --git a/.yarn/patches/mongodb-npm-4.17.2-40d1286d70.patch b/.yarn/patches/mongodb-npm-4.17.2-40d1286d70.patch deleted file mode 100644 index b34fbe1aa665..000000000000 --- a/.yarn/patches/mongodb-npm-4.17.2-40d1286d70.patch +++ /dev/null @@ -1,13 +0,0 @@ -diff --git a/mongodb.d.ts b/mongodb.d.ts -index 9696a0d0104095e8e4dfa4a4fe05fe81fd8b50c7..f5aa6e76fe6f2e6a55e6e2a720be15b7a6f98107 100644 ---- a/mongodb.d.ts -+++ b/mongodb.d.ts -@@ -5535,7 +5535,7 @@ export declare interface MonitorOptions extends Omit = Depth['length'] extends 8 ? [] : Type extends string | number | boolean | Date | RegExp | Buffer | Uint8Array | ((...args: any[]) => any) | { -+export declare type NestedPaths = Depth['length'] extends 3 ? [] : Type extends string | number | boolean | Date | RegExp | Buffer | Uint8Array | ((...args: any[]) => any) | { - _bsontype: string; - } ? [] : Type extends ReadonlyArray ? [] | [number, ...NestedPaths] : Type extends Map ? [string] : Type extends object ? { - [Key in Extract]: Type[Key] extends Type ? [Key] : Type extends Type[Key] ? [Key] : Type[Key] extends ReadonlyArray ? Type extends ArrayType ? [Key] : ArrayType extends Type ? [Key] : [ diff --git a/.yarn/patches/mongodb-npm-4.17.1-a2fe811ff1.patch b/.yarn/patches/mongodb-npm-6.10.0-b914157c35.patch similarity index 68% rename from .yarn/patches/mongodb-npm-4.17.1-a2fe811ff1.patch rename to .yarn/patches/mongodb-npm-6.10.0-b914157c35.patch index 501881370244..61cde9288c60 100644 --- a/.yarn/patches/mongodb-npm-4.17.1-a2fe811ff1.patch +++ b/.yarn/patches/mongodb-npm-6.10.0-b914157c35.patch @@ -1,13 +1,13 @@ diff --git a/mongodb.d.ts b/mongodb.d.ts -index dd080b553309594c28093365ea101adec5c0a20c..20a616de8c97ec68629c01a848ea8df4fe122bf2 100644 +index 8d68644d312c22d8c8c992ef0bc78431bffa2cf4..3f0a5664cd04bb2abb155288e3c245be72e8549f 100644 --- a/mongodb.d.ts +++ b/mongodb.d.ts -@@ -5539,7 +5539,7 @@ export declare interface MonitorOptions extends Omit = Depth['length'] extends 8 ? [] : Type extends string | number | boolean | Date | RegExp | Buffer | Uint8Array | ((...args: any[]) => any) | { -+export declare type NestedPaths = Depth['length'] extends 1 ? [] : Type extends string | number | boolean | Date | RegExp | Buffer | Uint8Array | ((...args: any[]) => any) | { +-export declare type NestedPaths = Depth['length'] extends 8 ? [] : Type extends string | number | bigint | boolean | Date | RegExp | Buffer | Uint8Array | ((...args: any[]) => any) | { ++export declare type NestedPaths = Depth['length'] extends 4 ? [] : Type extends string | number | bigint | boolean | Date | RegExp | Buffer | Uint8Array | ((...args: any[]) => any) | { _bsontype: string; } ? [] : Type extends ReadonlyArray ? [] | [number, ...NestedPaths] : Type extends Map ? [string] : Type extends object ? { [Key in Extract]: Type[Key] extends Type ? [Key] : Type extends Type[Key] ? [Key] : Type[Key] extends ReadonlyArray ? Type extends ArrayType ? [Key] : ArrayType extends Type ? [Key] : [ diff --git a/apps/meteor/.docker-mongo/Dockerfile b/apps/meteor/.docker-mongo/Dockerfile index 560fde4a69dc..faa3c6138ca9 100644 --- a/apps/meteor/.docker-mongo/Dockerfile +++ b/apps/meteor/.docker-mongo/Dockerfile @@ -1,4 +1,4 @@ -FROM node:20.18.0-bullseye-slim +FROM node:22.11.0-bullseye-slim LABEL maintainer="buildmaster@rocket.chat" diff --git a/apps/meteor/.docker/Dockerfile.alpine b/apps/meteor/.docker/Dockerfile.alpine index fbaf41f86a10..bb57d88126c9 100644 --- a/apps/meteor/.docker/Dockerfile.alpine +++ b/apps/meteor/.docker/Dockerfile.alpine @@ -1,4 +1,4 @@ -FROM node:20.18.0-alpine3.20 +FROM node:22.11.0-alpine3.20 LABEL maintainer="buildmaster@rocket.chat" diff --git a/apps/meteor/.docker/Dockerfile.debian b/apps/meteor/.docker/Dockerfile.debian index 22134532ece0..7b1094b46508 100644 --- a/apps/meteor/.docker/Dockerfile.debian +++ b/apps/meteor/.docker/Dockerfile.debian @@ -2,7 +2,7 @@ ARG DENO_VERSION="1.37.1" FROM denoland/deno:bin-${DENO_VERSION} as deno -FROM node:20.18.0-bullseye-slim +FROM node:22.11.0-bullseye-slim LABEL maintainer="buildmaster@rocket.chat" diff --git a/apps/meteor/.meteor/packages b/apps/meteor/.meteor/packages index ead1cc41fd09..1580bfe8365d 100644 --- a/apps/meteor/.meteor/packages +++ b/apps/meteor/.meteor/packages @@ -20,7 +20,7 @@ accounts-github@1.5.1 accounts-google@1.4.1 accounts-meteor-developer@1.5.1 accounts-oauth@1.4.5 -accounts-password@3.0.2 +accounts-password@3.0.3 accounts-twitter@1.5.2 google-oauth@1.4.5 @@ -30,18 +30,18 @@ oauth2@1.3.3 check@1.4.4 ddp-rate-limiter@1.2.2 rate-limit@1.1.2 -email@3.1.0 +email@3.1.1 meteor-base@1.5.2 ddp-common@1.4.4 -webapp@2.0.3 +webapp@2.0.4 -mongo@2.0.2 +mongo@2.0.3 reload@1.3.2 service-configuration@1.3.5 session@1.2.2 -shell-server@0.6.0 +shell-server@0.6.1 dispatch:run-as-user ostrio:cookies @@ -59,11 +59,11 @@ tracker@1.3.4 reactive-dict@1.3.2 reactive-var@1.0.13 -babel-compiler@7.11.1 +babel-compiler@7.11.2 standard-minifier-css@1.9.3 dynamic-import@0.7.4 -ecmascript@0.16.9 -typescript@5.4.3 +ecmascript@0.16.10 +typescript@5.6.3 autoupdate@2.0.0 diff --git a/apps/meteor/.meteor/release b/apps/meteor/.meteor/release index b1e86a359f7c..8d20e1a2d3a8 100644 --- a/apps/meteor/.meteor/release +++ b/apps/meteor/.meteor/release @@ -1 +1 @@ -METEOR@3.0.4 +METEOR@3.1 diff --git a/apps/meteor/.meteor/versions b/apps/meteor/.meteor/versions index 0f8f733b3148..5a84dc401a9b 100644 --- a/apps/meteor/.meteor/versions +++ b/apps/meteor/.meteor/versions @@ -4,11 +4,11 @@ accounts-github@1.5.1 accounts-google@1.4.1 accounts-meteor-developer@1.5.1 accounts-oauth@1.4.5 -accounts-password@3.0.2 +accounts-password@3.0.3 accounts-twitter@1.5.2 allow-deny@2.0.0 autoupdate@2.0.0 -babel-compiler@7.11.1 +babel-compiler@7.11.2 babel-runtime@1.5.2 base64@1.0.13 binary-heap@1.0.12 @@ -17,19 +17,19 @@ callback-hook@1.6.0 check@1.4.4 core-runtime@1.0.0 ddp@1.4.2 -ddp-client@3.0.2 +ddp-client@3.0.3 ddp-common@1.4.4 ddp-rate-limiter@1.2.2 -ddp-server@3.0.2 +ddp-server@3.0.3 diff-sequence@1.1.3 dispatch:run-as-user@1.1.1 dynamic-import@0.7.4 -ecmascript@0.16.9 +ecmascript@0.16.10 ecmascript-runtime@0.8.3 ecmascript-runtime-client@0.12.2 ecmascript-runtime-server@0.11.1 ejson@1.1.4 -email@3.1.0 +email@3.1.1 es5-shim@4.8.1 facebook-oauth@1.11.4 facts-base@1.0.2 @@ -44,20 +44,20 @@ inter-process-messaging@0.1.2 kadira:flow-router@2.12.1 localstorage@1.2.1 logging@1.3.5 -meteor@2.0.1 +meteor@2.0.2 meteor-base@1.5.2 meteor-developer-oauth@1.3.3 meteorhacks:inject-initial@1.0.5 minifier-css@2.0.0 -minimongo@2.0.1 +minimongo@2.0.2 modern-browsers@0.1.11 -modules@0.20.2 +modules@0.20.3 modules-runtime@0.13.2 -mongo@2.0.2 -mongo-decimal@0.1.4-beta300.7 +mongo@2.0.3 +mongo-decimal@0.2.0 mongo-dev-server@1.1.1 mongo-id@1.0.9 -npm-mongo@4.17.4 +npm-mongo@6.10.0 oauth@3.0.0 oauth1@1.5.2 oauth2@1.3.3 @@ -82,15 +82,15 @@ routepolicy@1.1.2 service-configuration@1.3.5 session@1.2.2 sha@1.0.10 -shell-server@0.6.0 +shell-server@0.6.1 socket-stream-client@0.5.3 standard-minifier-css@1.9.3 tracker@1.3.4 twitter-oauth@1.3.4 -typescript@5.4.3 +typescript@5.6.3 underscore@1.6.4 -url@1.3.4 -webapp@2.0.3 +url@1.3.5 +webapp@2.0.4 webapp-hashing@1.1.2 zodern:caching-minifier@0.5.0 zodern:standard-minifier-js@5.2.0 diff --git a/apps/meteor/.mocharc.js b/apps/meteor/.mocharc.js index f11b315b8cef..344cd772d49d 100644 --- a/apps/meteor/.mocharc.js +++ b/apps/meteor/.mocharc.js @@ -37,5 +37,6 @@ module.exports = { 'tests/unit/server/**/*.tests.ts', 'tests/unit/server/**/*.spec.ts', 'app/api/**/*.spec.ts', + 'app/file-upload/server/**/*.spec.ts', ], }; diff --git a/apps/meteor/CHANGELOG.md b/apps/meteor/CHANGELOG.md index d5319e745e35..725d884de851 100644 --- a/apps/meteor/CHANGELOG.md +++ b/apps/meteor/CHANGELOG.md @@ -1,5 +1,396 @@ # @rocket.chat/meteor +## 7.2.0 + +### Minor Changes + +- ([#34194](https://github.com/RocketChat/Rocket.Chat/pull/34194)) Adds a new `contacts.checkExistence` endpoint, which allows identifying whether there's already a registered contact using a given email, phone, id or visitor to source association. + +- ([#34004](https://github.com/RocketChat/Rocket.Chat/pull/34004)) Allows Rocket.Chat to store call events. + +- ([#33895](https://github.com/RocketChat/Rocket.Chat/pull/33895)) Adds statistics related to the new **Contact Identification** feature: + - `totalContacts`: Total number of contacts; + - `totalUnknownContacts`: Total number of unknown contacts; + - `totalMergedContacts`: Total number of merged contacts; + - `totalConflicts`: Total number of merge conflicts; + - `totalResolvedConflicts`: Total number of resolved conflicts; + - `totalBlockedContacts`: Total number of blocked contacts; + - `totalPartiallyBlockedContacts`: Total number of partially blocked contacts; + - `totalFullyBlockedContacts`: Total number of fully blocked contacts; + - `totalVerifiedContacts`: Total number of verified contacts; + - `avgChannelsPerContact`: Average number of channels per contact; + - `totalContactsWithoutChannels`: Number of contacts without channels; + - `totalImportedContacts`: Total number of imported contacts; + - `totalUpsellViews`: Total number of "Advanced Contact Management" Upsell CTA views; + - `totalUpsellClicks`: Total number of "Advanced Contact Management" Upsell CTA clicks; +- ([#34220](https://github.com/RocketChat/Rocket.Chat/pull/34220)) Disables OTR messages selection when exporting messages + +- ([#34121](https://github.com/RocketChat/Rocket.Chat/pull/34121)) Organizes App Settings interface by introducing section-based accordion groups to improve navigation and readability for administrators. + +- ([#34076](https://github.com/RocketChat/Rocket.Chat/pull/34076)) Introduces a new option when exporting messages, allowing users to select and download a JSON file directly from client + +- ([#34057](https://github.com/RocketChat/Rocket.Chat/pull/34057)) Improves the workspace and subscription admin pages by updating font scaling, centralizing elements, + enhancing responsiveness, and refactoring components to provide a better overall user experience. +- ([#33549](https://github.com/RocketChat/Rocket.Chat/pull/33549)) Adds a new callout in the subscription page to inform users of subscription upgrade eligibility when applicable. + +### Patch Changes + +- ([#34205](https://github.com/RocketChat/Rocket.Chat/pull/34205)) Fixes an error where the engine would not retry a subprocess restart if the last attempt failed + +- ([#34137](https://github.com/RocketChat/Rocket.Chat/pull/34137)) Fixes Unit's `numDepartments` property not being updated after a department is removed + +- Bump @rocket.chat/meteor version. + +- Bump @rocket.chat/meteor version. + +- Bump @rocket.chat/meteor version. + +- Bump @rocket.chat/meteor version. + +- ([#34038](https://github.com/RocketChat/Rocket.Chat/pull/34038)) Removes a validation that allowed only the room creator to propagate E2EE room keys. This was causing issues when the rooms were created via apps or some other integration, as the creator may not be online or able to create E2EE keys + +- ([#34089](https://github.com/RocketChat/Rocket.Chat/pull/34089)) Fixed an issue that caused clients to not properly receive certain server notifications right after login + +- ([#34858](https://github.com/RocketChat/Rocket.Chat/pull/34858)) Fixes an issue that prevented the apps-engine from reestablishing communications with subprocesses in some cases + +- ([#34013](https://github.com/RocketChat/Rocket.Chat/pull/34013)) Fixes issue that caused the livechat appearance form not be able to submit on CE servers + +- ([#33873](https://github.com/RocketChat/Rocket.Chat/pull/33873)) Fixes the incorrect registration status shown on admin users page for federated remote users. + +- ([#34156](https://github.com/RocketChat/Rocket.Chat/pull/34156)) Fixes "Average first response time" and "Best first response time" metrics being associated with the last agent who served the room (instead of the first one) + +- ([#33280](https://github.com/RocketChat/Rocket.Chat/pull/33280)) Fixes an issue preventing the creation of normal direct message rooms due to an invalid federation configuration, allowing proper room creation under standard settings. + +- ([#34187](https://github.com/RocketChat/Rocket.Chat/pull/34187)) Adds support for `Use Full Name Initials to Generate Default Avatar` setting for the generated avatar preview button when editing an User's avatar + +- ([#34130](https://github.com/RocketChat/Rocket.Chat/pull/34130)) Fixes an issue where room members menu doesn't display properly without enough space + +- ([#34079](https://github.com/RocketChat/Rocket.Chat/pull/34079)) Fixes missing images in Twitter article links to ensure proper display by relying on meta tags. + +- ([#34205](https://github.com/RocketChat/Rocket.Chat/pull/34205)) Fixes error propagation when trying to get the status of apps in some cases + +- ([#33253](https://github.com/RocketChat/Rocket.Chat/pull/33253)) Fixes an issue with Federation startup where the bridge would intermittently fail to start causing error being shown "Matrix Bridge isn't running yet". + +- ([#34062](https://github.com/RocketChat/Rocket.Chat/pull/34062)) Fixes condition causing Omnichannel queue to start more than once. + +- ([#34197](https://github.com/RocketChat/Rocket.Chat/pull/34197)) fixes "Change to language" button in login page not displaying the target language + +- ([#34148](https://github.com/RocketChat/Rocket.Chat/pull/34148)) Fixes messages not being processed for all slack servers + +- ([#34060](https://github.com/RocketChat/Rocket.Chat/pull/34060)) Fixes an issue where premium settings were using the wrong `Tag` variant in Omnichannel Appearance configuration + +- ([#34215](https://github.com/RocketChat/Rocket.Chat/pull/34215)) Fixes a UI issue that showed the incorrect migration number on the `Information` page. This was caused by a function calculating the stats before the server had migrated the database and updated the control. + +- ([#34124](https://github.com/RocketChat/Rocket.Chat/pull/34124)) Allows default avatars to be generated with more than one inital (limited to first 3) when setting `Use Full Name Initials to Generate Default Avatar` is true. + +- ([#34165](https://github.com/RocketChat/Rocket.Chat/pull/34165)) Fixes an issue where removing the only message of a thread would keep the unread thread messages badge + +- ([#34109](https://github.com/RocketChat/Rocket.Chat/pull/34109)) Fixes `im.counters` endpoint returning `null` on `unread` messages property for users that have never opened the queried DM + +- ([#34205](https://github.com/RocketChat/Rocket.Chat/pull/34205)) Fixes wrong data being reported to total failed apps metrics and statistics + +- ([#34080](https://github.com/RocketChat/Rocket.Chat/pull/34080)) Fixes sidepanel list not sorting by last message inside thread + +- ([#34092](https://github.com/RocketChat/Rocket.Chat/pull/34092)) fixes mail export form "To additional emails" field validation + +- ([#34174](https://github.com/RocketChat/Rocket.Chat/pull/34174)) Fixed an issue that added potencially infinite callbacks to the same event, degrading performance over time. + +- ([#34127](https://github.com/RocketChat/Rocket.Chat/pull/34127)) Fixes a behavior of the mentions parser that identified mentions inside markdown links text. Now, these components will be removed from the text before trying to parse mentions. + +- ([#34217](https://github.com/RocketChat/Rocket.Chat/pull/34217)) Fixes an issue where the update banner wasn't showing the new version number + +- ([#34101](https://github.com/RocketChat/Rocket.Chat/pull/34101)) Fixes an issue which caused action menu to be clipped in moderation page on smaller screens for better usability. + +- ([#33906](https://github.com/RocketChat/Rocket.Chat/pull/33906) by [@thepiyush-303](https://github.com/thepiyush-303)) Sorts the list of language options by name correctly + +- ([#34068](https://github.com/RocketChat/Rocket.Chat/pull/34068)) fixed an issue that caused the conference call ringer to fail to accept calls if the user logged out and in again + +- ([#34000](https://github.com/RocketChat/Rocket.Chat/pull/34000)) Fixes special characters not being escaped on sidepanel extended view + +- ([#34209](https://github.com/RocketChat/Rocket.Chat/pull/34209)) Fixed the data structure of the features preview + +- ([#34139](https://github.com/RocketChat/Rocket.Chat/pull/34139)) Fixes contact update failing in case a custom field is removed from the workspace + +- ([#34202](https://github.com/RocketChat/Rocket.Chat/pull/34202)) Fixes an issue where the notification sound was playing randomly + +-
Updated dependencies [b845fc0093cfaf59093d1e99ccaae77ab741354a, 76f6239ff1a9f34f163c03c140c4ceba62563b4e, f11efb4011db4efcdbf978d4b76671028daeed6e, eb794b7fd6bf3ff5a37a38bccaba247ed36db744, c43220dcd8c1df86a6143d6553964ad2173903b3, f23e71166a2dfee0e3394e49cac95c48e5eb62e5, 47f24c2fb795eee33cb021d56508298b8a548eec, f62326080d5e6ba36351cb0b6965a09f23856ac8, 76f6239ff1a9f34f163c03c140c4ceba62563b4e, f62326080d5e6ba36351cb0b6965a09f23856ac8, f90b1c99bdf4d89350a70c9ef4c2d12ed3784fd8, a129e3e1c9ba5930906ef609d7573e5708d336f0, 475120dc19fb8cc400fd8af21559cd6f3cc17eb8, b7e1dd38de051607c05f09c3dc70e4bfb94002b2, 2e4af86f6463166ba4d0b37b153b89ab246e112a, 76f6239ff1a9f34f163c03c140c4ceba62563b4e, f62326080d5e6ba36351cb0b6965a09f23856ac8, 2d41274ae21ec51e7382da92e2f4e0c36186f814, be2ede48ba7774a43189a729b385f441d088b68e, 75a14b2e013aca7361cac56316f2b7e8c07d9dc8, f62326080d5e6ba36351cb0b6965a09f23856ac8]: + + - @rocket.chat/rest-typings@7.2.0 + - @rocket.chat/fuselage-ui-kit@14.0.0 + - @rocket.chat/instance-status@0.1.11 + - @rocket.chat/ui-theming@0.4.1 + - @rocket.chat/model-typings@1.2.0 + - @rocket.chat/ui-video-conf@14.0.0 + - @rocket.chat/core-typings@7.2.0 + - @rocket.chat/apps-engine@1.48.1 + - @rocket.chat/ui-composer@0.5.0 + - @rocket.chat/ui-contexts@14.0.0 + - @rocket.chat/gazzodown@14.0.0 + - @rocket.chat/ui-avatar@10.0.0 + - @rocket.chat/ui-client@14.0.0 + - @rocket.chat/ui-voip@4.0.0 + - @rocket.chat/i18n@1.2.0 + - @rocket.chat/models@1.1.0 + - @rocket.chat/sha256@1.0.11 + - @rocket.chat/freeswitch@1.1.0 + - @rocket.chat/omnichannel-services@0.3.8 + - @rocket.chat/presence@0.2.11 + - @rocket.chat/api-client@0.2.11 + - @rocket.chat/core-services@0.7.3 + - @rocket.chat/apps@0.2.2 + - @rocket.chat/license@1.0.2 + - @rocket.chat/pdf-worker@0.2.8 + - @rocket.chat/cron@0.1.11 + - @rocket.chat/web-ui-registration@14.0.0 + - @rocket.chat/network-broker@0.1.3 + - @rocket.chat/server-cloud-communication@0.0.2 +
+ +## 7.2.0-rc.3 + +### Patch Changes + +- Bump @rocket.chat/meteor version. + +-
Updated dependencies []: + + - @rocket.chat/core-typings@7.2.0-rc.3 + - @rocket.chat/rest-typings@7.2.0-rc.3 + - @rocket.chat/license@1.0.2-rc.3 + - @rocket.chat/omnichannel-services@0.3.8-rc.3 + - @rocket.chat/pdf-worker@0.2.8-rc.3 + - @rocket.chat/presence@0.2.11-rc.3 + - @rocket.chat/api-client@0.2.11-rc.3 + - @rocket.chat/apps@0.2.2-rc.3 + - @rocket.chat/core-services@0.7.3-rc.3 + - @rocket.chat/cron@0.1.11-rc.3 + - @rocket.chat/freeswitch@1.1.0-rc.3 + - @rocket.chat/fuselage-ui-kit@14.0.0-rc.3 + - @rocket.chat/gazzodown@14.0.0-rc.3 + - @rocket.chat/model-typings@1.2.0-rc.3 + - @rocket.chat/ui-contexts@14.0.0-rc.3 + - @rocket.chat/server-cloud-communication@0.0.2 + - @rocket.chat/network-broker@0.1.3-rc.3 + - @rocket.chat/models@1.1.0-rc.3 + - @rocket.chat/ui-theming@0.4.1-rc.1 + - @rocket.chat/ui-avatar@10.0.0-rc.3 + - @rocket.chat/ui-client@14.0.0-rc.3 + - @rocket.chat/ui-video-conf@14.0.0-rc.3 + - @rocket.chat/ui-voip@4.0.0-rc.3 + - @rocket.chat/web-ui-registration@14.0.0-rc.3 + - @rocket.chat/instance-status@0.1.11-rc.3 +
+ +## 7.2.0-rc.2 + +### Patch Changes + +- Bump @rocket.chat/meteor version. + +- ([#34858](https://github.com/RocketChat/Rocket.Chat/pull/34858)) Fixes an issue that prevented the apps-engine from reestablishing communications with subprocesses in some cases + +-
Updated dependencies [c43220dcd8c1df86a6143d6553964ad2173903b3]: + + - @rocket.chat/fuselage-ui-kit@14.0.0-rc.2 + - @rocket.chat/ui-theming@0.4.1-rc.1 + - @rocket.chat/apps-engine@1.48.1-rc.1 + - @rocket.chat/ui-composer@0.5.0-rc.1 + - @rocket.chat/ui-contexts@14.0.0-rc.2 + - @rocket.chat/ui-client@14.0.0-rc.2 + - @rocket.chat/models@1.1.0-rc.2 + - @rocket.chat/sha256@1.0.11-rc.0 + - @rocket.chat/ui-voip@4.0.0-rc.2 + - @rocket.chat/web-ui-registration@14.0.0-rc.2 + - @rocket.chat/presence@0.2.11-rc.2 + - @rocket.chat/apps@0.2.2-rc.2 + - @rocket.chat/core-services@0.7.3-rc.2 + - @rocket.chat/core-typings@7.2.0-rc.2 + - @rocket.chat/rest-typings@7.2.0-rc.2 + - @rocket.chat/gazzodown@14.0.0-rc.2 + - @rocket.chat/ui-avatar@10.0.0-rc.2 + - @rocket.chat/ui-video-conf@14.0.0-rc.2 + - @rocket.chat/omnichannel-services@0.3.8-rc.2 + - @rocket.chat/cron@0.1.11-rc.2 + - @rocket.chat/instance-status@0.1.11-rc.2 + - @rocket.chat/network-broker@0.1.3-rc.2 + - @rocket.chat/license@1.0.2-rc.2 + - @rocket.chat/pdf-worker@0.2.8-rc.2 + - @rocket.chat/api-client@0.2.11-rc.2 + - @rocket.chat/freeswitch@1.1.0-rc.2 + - @rocket.chat/model-typings@1.2.0-rc.2 + - @rocket.chat/server-cloud-communication@0.0.2 +
+ +## 7.2.0-rc.1 + +### Patch Changes + +- Bump @rocket.chat/meteor version. + +-
Updated dependencies []: + + - @rocket.chat/core-typings@7.2.0-rc.1 + - @rocket.chat/rest-typings@7.2.0-rc.1 + - @rocket.chat/license@1.0.2-rc.1 + - @rocket.chat/omnichannel-services@0.3.8-rc.1 + - @rocket.chat/pdf-worker@0.2.8-rc.1 + - @rocket.chat/presence@0.2.11-rc.1 + - @rocket.chat/api-client@0.2.11-rc.1 + - @rocket.chat/apps@0.2.2-rc.1 + - @rocket.chat/core-services@0.7.3-rc.1 + - @rocket.chat/cron@0.1.11-rc.1 + - @rocket.chat/freeswitch@1.1.0-rc.1 + - @rocket.chat/fuselage-ui-kit@14.0.0-rc.1 + - @rocket.chat/gazzodown@14.0.0-rc.1 + - @rocket.chat/model-typings@1.2.0-rc.1 + - @rocket.chat/ui-contexts@14.0.0-rc.1 + - @rocket.chat/server-cloud-communication@0.0.2 + - @rocket.chat/network-broker@0.1.3-rc.1 + - @rocket.chat/models@1.1.0-rc.1 + - @rocket.chat/ui-theming@0.4.1-rc.0 + - @rocket.chat/ui-avatar@10.0.0-rc.1 + - @rocket.chat/ui-client@14.0.0-rc.1 + - @rocket.chat/ui-video-conf@14.0.0-rc.1 + - @rocket.chat/ui-voip@4.0.0-rc.1 + - @rocket.chat/web-ui-registration@14.0.0-rc.1 + - @rocket.chat/instance-status@0.1.11-rc.1 +
+ +## 7.2.0-rc.0 + +### Minor Changes + +- ([#34194](https://github.com/RocketChat/Rocket.Chat/pull/34194)) Adds a new `contacts.checkExistence` endpoint, which allows identifying whether there's already a registered contact using a given email, phone, id or visitor to source association. + +- ([#34004](https://github.com/RocketChat/Rocket.Chat/pull/34004)) Allows Rocket.Chat to store call events. + +- ([#33895](https://github.com/RocketChat/Rocket.Chat/pull/33895)) Adds statistics related to the new **Contact Identification** feature: + - `totalContacts`: Total number of contacts; + - `totalUnknownContacts`: Total number of unknown contacts; + - `totalMergedContacts`: Total number of merged contacts; + - `totalConflicts`: Total number of merge conflicts; + - `totalResolvedConflicts`: Total number of resolved conflicts; + - `totalBlockedContacts`: Total number of blocked contacts; + - `totalPartiallyBlockedContacts`: Total number of partially blocked contacts; + - `totalFullyBlockedContacts`: Total number of fully blocked contacts; + - `totalVerifiedContacts`: Total number of verified contacts; + - `avgChannelsPerContact`: Average number of channels per contact; + - `totalContactsWithoutChannels`: Number of contacts without channels; + - `totalImportedContacts`: Total number of imported contacts; + - `totalUpsellViews`: Total number of "Advanced Contact Management" Upsell CTA views; + - `totalUpsellClicks`: Total number of "Advanced Contact Management" Upsell CTA clicks; +- ([#34220](https://github.com/RocketChat/Rocket.Chat/pull/34220)) Disables OTR messages selection when exporting messages + +- ([#34121](https://github.com/RocketChat/Rocket.Chat/pull/34121)) Organizes App Settings interface by introducing section-based accordion groups to improve navigation and readability for administrators. + +- ([#34076](https://github.com/RocketChat/Rocket.Chat/pull/34076)) Introduces a new option when exporting messages, allowing users to select and download a JSON file directly from client + +- ([#34057](https://github.com/RocketChat/Rocket.Chat/pull/34057)) Improves the workspace and subscription admin pages by updating font scaling, centralizing elements, + enhancing responsiveness, and refactoring components to provide a better overall user experience. +- ([#33549](https://github.com/RocketChat/Rocket.Chat/pull/33549)) Adds a new callout in the subscription page to inform users of subscription upgrade eligibility when applicable. + +### Patch Changes + +- ([#34205](https://github.com/RocketChat/Rocket.Chat/pull/34205)) Fixes an error where the engine would not retry a subprocess restart if the last attempt failed + +- ([#34137](https://github.com/RocketChat/Rocket.Chat/pull/34137)) Fixes Unit's `numDepartments` property not being updated after a department is removed + +- ([#34038](https://github.com/RocketChat/Rocket.Chat/pull/34038)) Removes a validation that allowed only the room creator to propagate E2EE room keys. This was causing issues when the rooms were created via apps or some other integration, as the creator may not be online or able to create E2EE keys + +- ([#34089](https://github.com/RocketChat/Rocket.Chat/pull/34089)) Fixed an issue that caused clients to not properly receive certain server notifications right after login + +- ([#34013](https://github.com/RocketChat/Rocket.Chat/pull/34013)) Fixes issue that caused the livechat appearance form not be able to submit on CE servers + +- ([#33873](https://github.com/RocketChat/Rocket.Chat/pull/33873)) Fixes the incorrect registration status shown on admin users page for federated remote users. + +- ([#34156](https://github.com/RocketChat/Rocket.Chat/pull/34156)) Fixes "Average first response time" and "Best first response time" metrics being associated with the last agent who served the room (instead of the first one) + +- ([#33280](https://github.com/RocketChat/Rocket.Chat/pull/33280)) Fixes an issue preventing the creation of normal direct message rooms due to an invalid federation configuration, allowing proper room creation under standard settings. + +- ([#34187](https://github.com/RocketChat/Rocket.Chat/pull/34187)) Adds support for `Use Full Name Initials to Generate Default Avatar` setting for the generated avatar preview button when editing an User's avatar + +- ([#34130](https://github.com/RocketChat/Rocket.Chat/pull/34130)) Fixes an issue where room members menu doesn't display properly without enough space + +- ([#34079](https://github.com/RocketChat/Rocket.Chat/pull/34079)) Fixes missing images in Twitter article links to ensure proper display by relying on meta tags. + +- ([#34205](https://github.com/RocketChat/Rocket.Chat/pull/34205)) Fixes error propagation when trying to get the status of apps in some cases + +- ([#33253](https://github.com/RocketChat/Rocket.Chat/pull/33253)) Fixes an issue with Federation startup where the bridge would intermittently fail to start causing error being shown "Matrix Bridge isn't running yet". + +- ([#34062](https://github.com/RocketChat/Rocket.Chat/pull/34062)) Fixes condition causing Omnichannel queue to start more than once. + +- ([#34197](https://github.com/RocketChat/Rocket.Chat/pull/34197)) fixes "Change to language" button in login page not displaying the target language + +- ([#34148](https://github.com/RocketChat/Rocket.Chat/pull/34148)) Fixes messages not being processed for all slack servers + +- ([#34060](https://github.com/RocketChat/Rocket.Chat/pull/34060)) Fixes an issue where premium settings were using the wrong `Tag` variant in Omnichannel Appearance configuration + +- ([#34215](https://github.com/RocketChat/Rocket.Chat/pull/34215)) Fixes a UI issue that showed the incorrect migration number on the `Information` page. This was caused by a function calculating the stats before the server had migrated the database and updated the control. + +- ([#34124](https://github.com/RocketChat/Rocket.Chat/pull/34124)) Allows default avatars to be generated with more than one inital (limited to first 3) when setting `Use Full Name Initials to Generate Default Avatar` is true. + +- ([#34165](https://github.com/RocketChat/Rocket.Chat/pull/34165)) Fixes an issue where removing the only message of a thread would keep the unread thread messages badge + +- ([#34109](https://github.com/RocketChat/Rocket.Chat/pull/34109)) Fixes `im.counters` endpoint returning `null` on `unread` messages property for users that have never opened the queried DM + +- ([#34205](https://github.com/RocketChat/Rocket.Chat/pull/34205)) Fixes wrong data being reported to total failed apps metrics and statistics + +- ([#34080](https://github.com/RocketChat/Rocket.Chat/pull/34080)) Fixes sidepanel list not sorting by last message inside thread + +- ([#34092](https://github.com/RocketChat/Rocket.Chat/pull/34092)) fixes mail export form "To additional emails" field validation + +- ([#34174](https://github.com/RocketChat/Rocket.Chat/pull/34174)) Fixed an issue that added potencially infinite callbacks to the same event, degrading performance over time. + +- ([#34127](https://github.com/RocketChat/Rocket.Chat/pull/34127)) Fixes a behavior of the mentions parser that identified mentions inside markdown links text. Now, these components will be removed from the text before trying to parse mentions. + +- ([#34217](https://github.com/RocketChat/Rocket.Chat/pull/34217)) Fixes an issue where the update banner wasn't showing the new version number + +- ([#34101](https://github.com/RocketChat/Rocket.Chat/pull/34101)) Fixes an issue which caused action menu to be clipped in moderation page on smaller screens for better usability. + +- ([#33906](https://github.com/RocketChat/Rocket.Chat/pull/33906) by [@thepiyush-303](https://github.com/thepiyush-303)) Sorts the list of language options by name correctly + +- ([#34068](https://github.com/RocketChat/Rocket.Chat/pull/34068)) fixed an issue that caused the conference call ringer to fail to accept calls if the user logged out and in again + +- ([#34000](https://github.com/RocketChat/Rocket.Chat/pull/34000)) Fixes special characters not being escaped on sidepanel extended view + +- ([#34209](https://github.com/RocketChat/Rocket.Chat/pull/34209)) Fixed the data structure of the features preview + +- ([#34139](https://github.com/RocketChat/Rocket.Chat/pull/34139)) Fixes contact update failing in case a custom field is removed from the workspace + +- ([#34202](https://github.com/RocketChat/Rocket.Chat/pull/34202)) Fixes an issue where the notification sound was playing randomly + +-
Updated dependencies [b845fc0093cfaf59093d1e99ccaae77ab741354a, 76f6239ff1a9f34f163c03c140c4ceba62563b4e, f11efb4011db4efcdbf978d4b76671028daeed6e, eb794b7fd6bf3ff5a37a38bccaba247ed36db744, f23e71166a2dfee0e3394e49cac95c48e5eb62e5, 47f24c2fb795eee33cb021d56508298b8a548eec, f62326080d5e6ba36351cb0b6965a09f23856ac8, 76f6239ff1a9f34f163c03c140c4ceba62563b4e, f62326080d5e6ba36351cb0b6965a09f23856ac8, f90b1c99bdf4d89350a70c9ef4c2d12ed3784fd8, a129e3e1c9ba5930906ef609d7573e5708d336f0, 475120dc19fb8cc400fd8af21559cd6f3cc17eb8, b7e1dd38de051607c05f09c3dc70e4bfb94002b2, 2e4af86f6463166ba4d0b37b153b89ab246e112a, 76f6239ff1a9f34f163c03c140c4ceba62563b4e, f62326080d5e6ba36351cb0b6965a09f23856ac8, 2d41274ae21ec51e7382da92e2f4e0c36186f814, be2ede48ba7774a43189a729b385f441d088b68e, 75a14b2e013aca7361cac56316f2b7e8c07d9dc8, f62326080d5e6ba36351cb0b6965a09f23856ac8]: + + - @rocket.chat/rest-typings@7.2.0-rc.0 + - @rocket.chat/fuselage-ui-kit@14.0.0-rc.0 + - @rocket.chat/instance-status@0.1.11-rc.0 + - @rocket.chat/ui-theming@0.4.1-rc.0 + - @rocket.chat/model-typings@1.2.0-rc.0 + - @rocket.chat/ui-video-conf@14.0.0-rc.0 + - @rocket.chat/core-typings@7.2.0-rc.0 + - @rocket.chat/apps-engine@1.48.1-rc.0 + - @rocket.chat/ui-composer@0.5.0-rc.0 + - @rocket.chat/ui-contexts@14.0.0-rc.0 + - @rocket.chat/gazzodown@14.0.0-rc.0 + - @rocket.chat/ui-avatar@10.0.0-rc.0 + - @rocket.chat/ui-client@14.0.0-rc.0 + - @rocket.chat/ui-voip@4.0.0-rc.0 + - @rocket.chat/i18n@1.2.0-rc.0 + - @rocket.chat/freeswitch@1.1.0-rc.0 + - @rocket.chat/models@1.1.0-rc.0 + - @rocket.chat/omnichannel-services@0.3.8-rc.0 + - @rocket.chat/presence@0.2.11-rc.0 + - @rocket.chat/api-client@0.2.11-rc.0 + - @rocket.chat/core-services@0.7.3-rc.0 + - @rocket.chat/apps@0.2.2-rc.0 + - @rocket.chat/license@1.0.2-rc.0 + - @rocket.chat/pdf-worker@0.2.8-rc.0 + - @rocket.chat/cron@0.1.11-rc.0 + - @rocket.chat/web-ui-registration@14.0.0-rc.0 + - @rocket.chat/network-broker@0.1.3-rc.0 + - @rocket.chat/server-cloud-communication@0.0.2 +
+ ## 7.1.0 ### Minor Changes diff --git a/apps/meteor/app/api/server/lib/emailInbox.ts b/apps/meteor/app/api/server/lib/emailInbox.ts index 304d297261af..b3012fe1a6cb 100644 --- a/apps/meteor/app/api/server/lib/emailInbox.ts +++ b/apps/meteor/app/api/server/lib/emailInbox.ts @@ -78,19 +78,19 @@ export const updateEmailInbox = async ( const updatedResponse = await EmailInbox.updateById(_id, updateEmailInbox); - if (!updatedResponse.value) { + if (!updatedResponse) { throw new Error('error-invalid-email-inbox'); } void notifyOnEmailInboxChanged( { - ...updatedResponse.value, + ...updatedResponse, ...(department === 'All' && { department: undefined }), }, 'updated', ); - return updatedResponse.value; + return updatedResponse; }; export const removeEmailInbox = async (emailInboxId: IEmailInbox['_id']): Promise => { diff --git a/apps/meteor/app/apps/server/bridges/scheduler.ts b/apps/meteor/app/apps/server/bridges/scheduler.ts index 2f4799c79d70..6fdd3d69f953 100644 --- a/apps/meteor/app/apps/server/bridges/scheduler.ts +++ b/apps/meteor/app/apps/server/bridges/scheduler.ts @@ -4,7 +4,7 @@ import type { IAppServerOrchestrator } from '@rocket.chat/apps'; import type { IProcessor, IOnetimeSchedule, IRecurringSchedule, IJobContext } from '@rocket.chat/apps-engine/definition/scheduler'; import { StartupType } from '@rocket.chat/apps-engine/definition/scheduler'; import { SchedulerBridge } from '@rocket.chat/apps-engine/server/bridges/SchedulerBridge'; -import { ObjectID } from 'bson'; +import { ObjectId } from 'bson'; import { MongoInternals } from 'meteor/mongo'; function _callProcessor(processor: IProcessor['processor']): (job: Job) => Promise { @@ -159,7 +159,7 @@ export class AppSchedulerBridge extends SchedulerBridge { let cancelQuery; try { - cancelQuery = { _id: new ObjectID(jobId.split('_')[0]) }; + cancelQuery = { _id: new ObjectId(jobId.split('_')[0]) }; } catch (jobDocIdError) { // it is not a valid objectid, so it won't try to cancel by document id cancelQuery = { name: jobId }; diff --git a/apps/meteor/app/apps/server/bridges/settings.ts b/apps/meteor/app/apps/server/bridges/settings.ts index cada833aadbd..b3e6aaff32a4 100644 --- a/apps/meteor/app/apps/server/bridges/settings.ts +++ b/apps/meteor/app/apps/server/bridges/settings.ts @@ -75,7 +75,7 @@ export class AppSettingBridge extends ServerSettingBridge { throw new Error(`The setting "${id}" is not readable.`); } - const { value: setting } = await Settings.incrementValueById(id, value, { returnDocument: 'after' }); + const setting = await Settings.incrementValueById(id, value, { returnDocument: 'after' }); if (setting) { void notifyOnSettingChanged(setting); } diff --git a/apps/meteor/app/assets/server/assets.ts b/apps/meteor/app/assets/server/assets.ts index e9160b0ece61..c6df82fcc793 100644 --- a/apps/meteor/app/assets/server/assets.ts +++ b/apps/meteor/app/assets/server/assets.ts @@ -434,7 +434,8 @@ const listener = (req: IncomingMessage, res: ServerResponse, next: NextHandleFun if (asset && Array.isArray(asset.constraints.extensions) && !asset.constraints.extensions.includes(format)) { res.writeHead(403); - return res.end(); + res.end(); + return; } if (!file) { const defaultUrl = asset?.defaultUrl; diff --git a/apps/meteor/app/discussion/server/hooks/propagateDiscussionMetadata.ts b/apps/meteor/app/discussion/server/hooks/propagateDiscussionMetadata.ts index 1ff9ed1dc1ba..f2f02ce8a2c2 100644 --- a/apps/meteor/app/discussion/server/hooks/propagateDiscussionMetadata.ts +++ b/apps/meteor/app/discussion/server/hooks/propagateDiscussionMetadata.ts @@ -6,7 +6,7 @@ import { deleteRoom } from '../../../lib/server/functions/deleteRoom'; import { notifyOnMessageChange } from '../../../lib/server/lib/notifyListener'; const updateAndNotifyParentRoomWithParentMessage = async (room: IRoom): Promise => { - const { value: parentMessage } = await Messages.refreshDiscussionMetadata(room); + const parentMessage = await Messages.refreshDiscussionMetadata(room); if (!parentMessage) { return; } diff --git a/apps/meteor/app/e2e/server/functions/provideUsersSuggestedGroupKeys.ts b/apps/meteor/app/e2e/server/functions/provideUsersSuggestedGroupKeys.ts index c5b54e368823..44563daa2cc3 100644 --- a/apps/meteor/app/e2e/server/functions/provideUsersSuggestedGroupKeys.ts +++ b/apps/meteor/app/e2e/server/functions/provideUsersSuggestedGroupKeys.ts @@ -22,12 +22,7 @@ export const provideUsersSuggestedGroupKeys = async ( const usersWithSuggestedKeys = []; for await (const user of usersSuggestedGroupKeys[roomId]) { - const { value } = await Subscriptions.setGroupE2ESuggestedKeyAndOldRoomKeys( - user._id, - roomId, - user.key, - parseOldKeysDates(user.oldKeys), - ); + const value = await Subscriptions.setGroupE2ESuggestedKeyAndOldRoomKeys(user._id, roomId, user.key, parseOldKeysDates(user.oldKeys)); if (!value) { continue; } diff --git a/apps/meteor/app/e2e/server/functions/resetRoomKey.ts b/apps/meteor/app/e2e/server/functions/resetRoomKey.ts index 89a0058e48ae..ba9704c5c1a5 100644 --- a/apps/meteor/app/e2e/server/functions/resetRoomKey.ts +++ b/apps/meteor/app/e2e/server/functions/resetRoomKey.ts @@ -80,11 +80,11 @@ export async function resetRoomKey(roomId: string, userId: string, newRoomKey: s // And set the new key to the user that called the func const result = await Subscriptions.setE2EKeyByUserIdAndRoomId(userId, roomId, newRoomKey); - if (result.value) { - void notifyOnSubscriptionChanged(result.value); + if (result) { + void notifyOnSubscriptionChanged(result); } - if (roomResult.value) { - void notifyOnRoomChanged(roomResult.value); + if (roomResult) { + void notifyOnRoomChanged(roomResult); } } diff --git a/apps/meteor/app/e2e/server/methods/updateGroupKey.ts b/apps/meteor/app/e2e/server/methods/updateGroupKey.ts index 5f7860107bd9..f59a3d836d3b 100644 --- a/apps/meteor/app/e2e/server/methods/updateGroupKey.ts +++ b/apps/meteor/app/e2e/server/methods/updateGroupKey.ts @@ -40,7 +40,7 @@ export async function updateGroupKey(rid: string, uid: string, key: string, call } // uid also has subscription to this room - const { value } = await Subscriptions.setGroupE2ESuggestedKey(uid, rid, key); + const value = await Subscriptions.setGroupE2ESuggestedKey(uid, rid, key); if (value) { void notifyOnSubscriptionChanged(value); } diff --git a/apps/meteor/app/error-handler/server/lib/RocketChat.ErrorHandler.ts b/apps/meteor/app/error-handler/server/lib/RocketChat.ErrorHandler.ts index 24224a599abf..68300cb24e59 100644 --- a/apps/meteor/app/error-handler/server/lib/RocketChat.ErrorHandler.ts +++ b/apps/meteor/app/error-handler/server/lib/RocketChat.ErrorHandler.ts @@ -7,7 +7,7 @@ import { settings } from '../../../settings/server'; const incException = throttledCounter((counter) => { Settings.incrementValueById('Uncaught_Exceptions_Count', counter, { returnDocument: 'after' }) - .then(({ value }) => { + .then((value) => { if (value) { settings.set(value); } diff --git a/apps/meteor/app/file-upload/server/index.ts b/apps/meteor/app/file-upload/server/index.ts index 52a2b7f21da8..ff2fc4fabf36 100644 --- a/apps/meteor/app/file-upload/server/index.ts +++ b/apps/meteor/app/file-upload/server/index.ts @@ -1,6 +1,5 @@ import '../lib/FileUploadBase'; import { FileUpload } from './lib/FileUpload'; -import './lib/proxy'; import './lib/requests'; import './config/_configUploadStorage'; import './methods/sendFileMessage'; diff --git a/apps/meteor/app/file-upload/server/lib/FileUpload.spec.ts b/apps/meteor/app/file-upload/server/lib/FileUpload.spec.ts new file mode 100644 index 000000000000..73249fea904a --- /dev/null +++ b/apps/meteor/app/file-upload/server/lib/FileUpload.spec.ts @@ -0,0 +1,103 @@ +import { expect } from 'chai'; +import { before, beforeEach, describe, it } from 'mocha'; +import proxyquire from 'proxyquire'; +import sinon from 'sinon'; + +import { createFakeMessageWithAttachment } from '../../../../tests/mocks/data'; + +const fakeStorageModel = { findOneById: sinon.stub(), deleteFile: sinon.stub() }; +const settingsStub = { watch: sinon.stub(), get: sinon.stub() }; +const settingsGetMap = new Map(); +const messagesModelStub = { + find: sinon.stub(), +}; + +const { FileUpload, FileUploadClass } = proxyquire.noCallThru().load('./FileUpload', { + '@rocket.chat/models': { + Messages: messagesModelStub, + }, + 'meteor/check': sinon.stub(), + 'meteor/meteor': sinon.stub(), + 'meteor/ostrio:cookies': { Cookies: sinon.stub() }, + 'sharp': sinon.stub(), + 'stream-buffers': sinon.stub(), + './streamToBuffer': sinon.stub(), + '../../../../server/lib/i18n': sinon.stub(), + '../../../../server/lib/logger/system': sinon.stub(), + '../../../../server/lib/rooms/roomCoordinator': sinon.stub(), + '../../../../server/ufs': sinon.stub(), + '../../../../server/ufs/ufs-methods': sinon.stub(), + '../../../settings/server': { settings: settingsStub }, + '../../../utils/lib/mimeTypes': sinon.stub(), + '../../../utils/server/lib/JWTHelper': sinon.stub(), + '../../../utils/server/restrictions': sinon.stub(), +}); + +describe('FileUpload', () => { + before(() => { + new FileUploadClass({ name: 'fakeStorage:Uploads', model: fakeStorageModel, store: {} }); + settingsGetMap.set('FileUpload_Storage_Type', 'fakeStorage'); + settingsStub.get.callsFake((settingName) => settingsGetMap.get(settingName)); + }); + + beforeEach(() => { + messagesModelStub.find.reset(); + fakeStorageModel.findOneById.reset(); + fakeStorageModel.deleteFile.reset(); + }); + + it('should not remove any file if no room id is provided', async () => { + expect(await FileUpload.removeFilesByRoomId()).to.be.undefined; + + expect(messagesModelStub.find.called).to.be.false; + expect(fakeStorageModel.findOneById.called).to.be.false; + }); + + it('should not remove any file if an empty room id is provided', async () => { + expect(await FileUpload.removeFilesByRoomId('')).to.be.undefined; + + expect(messagesModelStub.find.called).to.be.false; + expect(fakeStorageModel.findOneById.called).to.be.false; + }); + + it('should not remove any file if an invalid room id is provided', async () => { + messagesModelStub.find.returns([]); + expect(await FileUpload.removeFilesByRoomId('invalid')).to.be.undefined; + + expect(messagesModelStub.find.called).to.be.true; + expect(fakeStorageModel.findOneById.called).to.be.false; + }); + + it('should delete file from storage if message contains a single file', async () => { + fakeStorageModel.findOneById.resolves({ _id: 'file-id', store: 'fakeStorage:Uploads' }); + + const fakeMessage = createFakeMessageWithAttachment(); + messagesModelStub.find.returns([fakeMessage]); + expect(await FileUpload.removeFilesByRoomId('invalid')).to.be.undefined; + + expect(messagesModelStub.find.called).to.be.true; + expect(fakeStorageModel.findOneById.calledOnceWith(fakeMessage.files?.[0]._id)).to.be.true; + expect(fakeStorageModel.deleteFile.calledOnceWith('file-id')).to.be.true; + }); + + it('should delete multiple files from storage if message contains many files (e.g. image and thumbnail)', async () => { + fakeStorageModel.findOneById.callsFake((_id) => ({ _id, store: 'fakeStorage:Uploads' })); + + const fakeMessage = createFakeMessageWithAttachment({ + files: [ + { _id: 'file-id', name: 'image', size: 100, type: 'image/png', format: 'png' }, + { _id: 'thumbnail-id', name: 'thumbnail-image', size: 25, type: 'image/png', format: 'png' }, + ], + }); + messagesModelStub.find.returns([fakeMessage]); + expect(await FileUpload.removeFilesByRoomId('invalid')).to.be.undefined; + + expect(messagesModelStub.find.called).to.be.true; + expect(fakeStorageModel.findOneById.calledTwice).to.be.true; + expect(fakeStorageModel.findOneById.calledWith('file-id')).to.be.true; + expect(fakeStorageModel.findOneById.calledWith('thumbnail-id')).to.be.true; + expect(fakeStorageModel.deleteFile.calledTwice).to.be.true; + expect(fakeStorageModel.deleteFile.calledWith('file-id')).to.be.true; + expect(fakeStorageModel.deleteFile.calledWith('thumbnail-id')).to.be.true; + }); +}); diff --git a/apps/meteor/app/file-upload/server/lib/FileUpload.ts b/apps/meteor/app/file-upload/server/lib/FileUpload.ts index cffdfe6288f2..7d4dfff28927 100644 --- a/apps/meteor/app/file-upload/server/lib/FileUpload.ts +++ b/apps/meteor/app/file-upload/server/lib/FileUpload.ts @@ -638,20 +638,20 @@ export const FileUpload = { const cursor = Messages.find( { rid, - 'file._id': { + 'files._id': { $exists: true, }, }, { projection: { - 'file._id': 1, + 'files._id': 1, }, }, ); for await (const document of cursor) { - if (document.file) { - await FileUpload.getStore('Uploads').deleteById(document.file._id); + if (document.files) { + await Promise.all(document.files.map((file) => FileUpload.getStore('Uploads').deleteById(file._id))); } } }, diff --git a/apps/meteor/app/file-upload/server/lib/proxy.ts b/apps/meteor/app/file-upload/server/lib/proxy.ts deleted file mode 100644 index dd9e692f0f98..000000000000 --- a/apps/meteor/app/file-upload/server/lib/proxy.ts +++ /dev/null @@ -1,113 +0,0 @@ -import http from 'http'; -import URL from 'url'; - -import { InstanceStatus } from '@rocket.chat/instance-status'; -import { Logger } from '@rocket.chat/logger'; -import { InstanceStatus as InstanceStatusModel } from '@rocket.chat/models'; -import type { NextFunction } from 'connect'; -import type createServer from 'connect'; -import { WebApp } from 'meteor/webapp'; - -import { UploadFS } from '../../../../server/ufs'; -import { isDocker } from '../../../utils/server/functions/isDocker'; - -const logger = new Logger('UploadProxy'); - -async function handle(req: createServer.IncomingMessage, res: http.ServerResponse, next: NextFunction) { - // Quick check to see if request should be catch - if (!req.url?.includes(`/${UploadFS.config.storesPath}/`)) { - return next(); - } - - logger.debug({ msg: 'Upload URL:', url: req.url }); - - if (req.method !== 'POST') { - return next(); - } - - // Remove store path - const parsedUrl = URL.parse(req.url); - const path = parsedUrl.pathname?.substr(UploadFS.config.storesPath.length + 1) || ''; - - // Get store - const regExp = new RegExp('^/([^/?]+)/([^/?]+)$'); - const match = regExp.exec(path); - - // Request is not valid - if (match === null) { - res.writeHead(400); - res.end(); - return; - } - - // Get store - const store = UploadFS.getStore(match[1]); - if (!store) { - res.writeHead(404); - res.end(); - return; - } - - // Get file - const fileId = match[2]; - const file = await store.getCollection().findOne({ _id: fileId }); - if (!file) { - res.writeHead(404); - res.end(); - return; - } - - if (!file.instanceId || file.instanceId === InstanceStatus.id()) { - logger.debug('Correct instance'); - return next(); - } - - // Proxy to other instance - const instance = await InstanceStatusModel.findOneById(file.instanceId); - - if (instance == null) { - res.writeHead(404); - res.end(); - return; - } - - if (instance.extraInformation.host === process.env.INSTANCE_IP && isDocker() === false) { - instance.extraInformation.host = 'localhost'; - } - - logger.debug(`Wrong instance, proxing to ${instance.extraInformation.host}:${instance.extraInformation.port}`); - - const options = { - hostname: instance.extraInformation.host, - port: instance.extraInformation.port, - path: req.originalUrl, - method: 'POST', - }; - - logger.warn( - 'UFS proxy middleware is deprecated as this upload method is not being used by Web/Mobile Clients. See this: https://docs.rocket.chat/api/rest-api/methods/rooms/upload', - ); - // eslint-disable-next-line @typescript-eslint/naming-convention - const proxy = http.request(options, (proxy_res) => { - proxy_res.pipe(res, { - end: true, - }); - }); - - req.pipe(proxy, { - end: true, - }); -} - -// @ts-expect-error - l -const dummyRouter = WebApp.connectHandlers._router; - -// Create a dummy route -dummyRouter.route('*'); -// fetch the newly created "layer" -const stackedRoute = dummyRouter.stack.pop(); -stackedRoute.handle = handle; - -// Move the layer to the top :) -// @ts-expect-error - l -WebApp.connectHandlers._router.stack.unshift(stackedRoute); diff --git a/apps/meteor/app/file-upload/server/lib/requests.ts b/apps/meteor/app/file-upload/server/lib/requests.ts index d50a7d594ca7..ad780116de0f 100644 --- a/apps/meteor/app/file-upload/server/lib/requests.ts +++ b/apps/meteor/app/file-upload/server/lib/requests.ts @@ -12,12 +12,14 @@ WebApp.connectHandlers.use(FileUpload.getPath(), async (req, res, next) => { if (file) { if (!(await FileUpload.requestCanAccessFiles(req, file))) { res.writeHead(403); - return res.end(); + res.end(); + return; } res.setHeader('Content-Security-Policy', "default-src 'none'"); res.setHeader('Cache-Control', 'max-age=31536000'); - return FileUpload.get(file, req, res, next); + await FileUpload.get(file, req, res, next); + return; } } diff --git a/apps/meteor/app/file/server/file.server.ts b/apps/meteor/app/file/server/file.server.ts index 3d4f6cf02609..94163e314145 100644 --- a/apps/meteor/app/file/server/file.server.ts +++ b/apps/meteor/app/file/server/file.server.ts @@ -2,14 +2,13 @@ import type { ReadStream } from 'fs'; import fs from 'fs'; import fsp from 'fs/promises'; import path from 'path'; -import stream from 'stream'; +import { Readable } from 'stream'; import type { ObjectId } from 'bson'; import { MongoInternals } from 'meteor/mongo'; +import { NpmModuleMongodb } from 'meteor/npm-mongo'; import mime from 'mime-type/with-db'; import mkdirp from 'mkdirp'; -import type { GridFSBucketReadStream } from 'mongodb'; -import { GridFSBucket } from 'mongodb'; const { db } = MongoInternals.defaultRemoteCollectionDriver().mongo; @@ -29,7 +28,7 @@ interface IRocketChatFileStore { getFileWithReadStream(fileName: string): Promise< | { - readStream: GridFSBucketReadStream | ReadStream; + readStream: NpmModuleMongodb.GridFSBucketReadStream | ReadStream; contentType?: string; length: number; uploadDate?: Date; @@ -45,12 +44,12 @@ interface IRocketChatFileStore { class GridFS implements IRocketChatFileStore { private name: string; - private bucket: GridFSBucket; + private bucket: NpmModuleMongodb.GridFSBucket; constructor({ name = 'file' } = {}) { this.name = name; - this.bucket = new GridFSBucket(db, { bucketName: this.name }); + this.bucket = new NpmModuleMongodb.GridFSBucket(db as any, { bucketName: this.name }); } private async findOne(filename: string) { @@ -207,9 +206,7 @@ class FileSystem implements IRocketChatFileStore { export const RocketChatFile = { bufferToStream(buffer: Buffer) { - const bufferStream = new stream.PassThrough(); - bufferStream.end(buffer); - return bufferStream; + return Readable.from(buffer); }, dataURIParse(dataURI: string | Buffer) { diff --git a/apps/meteor/app/importer-csv/server/CsvImporter.ts b/apps/meteor/app/importer-csv/server/CsvImporter.ts index 88cd39a84758..4f5eeba7d88b 100644 --- a/apps/meteor/app/importer-csv/server/CsvImporter.ts +++ b/apps/meteor/app/importer-csv/server/CsvImporter.ts @@ -251,7 +251,7 @@ export class CsvImporter extends Importer { } if (usersCount) { - const { value } = await Settings.incrementValueById('CSV_Importer_Count', usersCount, { returnDocument: 'after' }); + const value = await Settings.incrementValueById('CSV_Importer_Count', usersCount, { returnDocument: 'after' }); if (value) { void notifyOnSettingChanged(value); } diff --git a/apps/meteor/app/importer-slack-users/server/SlackUsersImporter.ts b/apps/meteor/app/importer-slack-users/server/SlackUsersImporter.ts index ae8df1859086..c05c6da8d690 100644 --- a/apps/meteor/app/importer-slack-users/server/SlackUsersImporter.ts +++ b/apps/meteor/app/importer-slack-users/server/SlackUsersImporter.ts @@ -95,7 +95,7 @@ export class SlackUsersImporter extends Importer { await super.updateProgress(ProgressStep.USER_SELECTION); await super.addCountToTotal(userCount); - const { value } = await Settings.incrementValueById('Slack_Users_Importer_Count', userCount, { returnDocument: 'after' }); + const value = await Settings.incrementValueById('Slack_Users_Importer_Count', userCount, { returnDocument: 'after' }); if (value) { void notifyOnSettingChanged(value); } diff --git a/apps/meteor/app/importer-slack/server/SlackImporter.ts b/apps/meteor/app/importer-slack/server/SlackImporter.ts index 59c07d26e969..c7e1b7c624ce 100644 --- a/apps/meteor/app/importer-slack/server/SlackImporter.ts +++ b/apps/meteor/app/importer-slack/server/SlackImporter.ts @@ -338,7 +338,7 @@ export class SlackImporter extends Importer { } if (userCount) { - const { value } = await Settings.incrementValueById('Slack_Importer_Count', userCount, { returnDocument: 'after' }); + const value = await Settings.incrementValueById('Slack_Importer_Count', userCount, { returnDocument: 'after' }); if (value) { void notifyOnSettingChanged(value); } diff --git a/apps/meteor/app/importer/server/classes/Importer.ts b/apps/meteor/app/importer/server/classes/Importer.ts index 32834ed15c4a..5629daab0508 100644 --- a/apps/meteor/app/importer/server/classes/Importer.ts +++ b/apps/meteor/app/importer/server/classes/Importer.ts @@ -184,7 +184,7 @@ export class Importer { }; const afterContactsBatchFn = async (successCount: number) => { - const { value } = await Settings.incrementValueById('Contacts_Importer_Count', successCount, { returnDocument: 'after' }); + const value = await Settings.incrementValueById('Contacts_Importer_Count', successCount, { returnDocument: 'after' }); if (value) { void notifyOnSettingChanged(value); } diff --git a/apps/meteor/app/integrations/server/methods/incoming/updateIncomingIntegration.ts b/apps/meteor/app/integrations/server/methods/incoming/updateIncomingIntegration.ts index cdf0d4465309..1ce65a03deb0 100644 --- a/apps/meteor/app/integrations/server/methods/incoming/updateIncomingIntegration.ts +++ b/apps/meteor/app/integrations/server/methods/incoming/updateIncomingIntegration.ts @@ -194,10 +194,10 @@ Meteor.methods({ }, ); - if (updatedIntegration.value) { - void notifyOnIntegrationChanged(updatedIntegration.value); + if (updatedIntegration) { + void notifyOnIntegrationChanged(updatedIntegration); } - return updatedIntegration.value; + return updatedIntegration; }, }); diff --git a/apps/meteor/app/integrations/server/methods/outgoing/updateOutgoingIntegration.ts b/apps/meteor/app/integrations/server/methods/outgoing/updateOutgoingIntegration.ts index 6ee39d81a588..e4c1c48e0487 100644 --- a/apps/meteor/app/integrations/server/methods/outgoing/updateOutgoingIntegration.ts +++ b/apps/meteor/app/integrations/server/methods/outgoing/updateOutgoingIntegration.ts @@ -111,10 +111,10 @@ Meteor.methods({ }, ); - if (updatedIntegration.value) { - await notifyOnIntegrationChanged(updatedIntegration.value); + if (updatedIntegration) { + await notifyOnIntegrationChanged(updatedIntegration); } - return updatedIntegration.value; + return updatedIntegration; }, }); diff --git a/apps/meteor/app/invites/server/functions/sendInvitationEmail.ts b/apps/meteor/app/invites/server/functions/sendInvitationEmail.ts index 87b8133e3491..900aeea9fdb1 100644 --- a/apps/meteor/app/invites/server/functions/sendInvitationEmail.ts +++ b/apps/meteor/app/invites/server/functions/sendInvitationEmail.ts @@ -54,7 +54,7 @@ export const sendInvitationEmail = async (userId: string, emails: string[]) => { }, }); - const { value } = await Settings.incrementValueById('Invitation_Email_Count', 1, { returnDocument: 'after' }); + const value = await Settings.incrementValueById('Invitation_Email_Count', 1, { returnDocument: 'after' }); if (value) { void notifyOnSettingChanged(value); } diff --git a/apps/meteor/app/lib/server/functions/deleteMessage.ts b/apps/meteor/app/lib/server/functions/deleteMessage.ts index 30044dadb81c..391ba936241f 100644 --- a/apps/meteor/app/lib/server/functions/deleteMessage.ts +++ b/apps/meteor/app/lib/server/functions/deleteMessage.ts @@ -109,7 +109,7 @@ export async function deleteMessage(message: IMessage, user: IUser): Promise { - const { value: updatedParentMessage } = await Messages.decreaseReplyCountById(message.tmid, -1); + const updatedParentMessage = await Messages.decreaseReplyCountById(message.tmid, -1); if (room) { const { modifiedCount } = await Subscriptions.removeUnreadThreadsByRoomId(room._id, [message.tmid]); diff --git a/apps/meteor/app/lib/server/functions/saveUser/handleBio.ts b/apps/meteor/app/lib/server/functions/saveUser/handleBio.ts index 1d2f572f5cd9..71dcbb783f84 100644 --- a/apps/meteor/app/lib/server/functions/saveUser/handleBio.ts +++ b/apps/meteor/app/lib/server/functions/saveUser/handleBio.ts @@ -1,22 +1,20 @@ import { MeteorError } from '@rocket.chat/core-services'; -import type { DeepPartial, DeepWritable, IUser } from '@rocket.chat/core-typings'; -import type { UpdateFilter } from 'mongodb'; +import type { IUser } from '@rocket.chat/core-typings'; +import type { Updater } from '@rocket.chat/model-typings'; import type { SaveUserData } from './saveUser'; const MAX_BIO_LENGTH = 260; -export const handleBio = (updateUser: DeepWritable>>, bio: SaveUserData['bio']) => { +export const handleBio = (userUpdater: Updater, bio: SaveUserData['bio']) => { if (bio?.trim()) { if (bio.length > MAX_BIO_LENGTH) { throw new MeteorError('error-bio-size-exceeded', `Bio size exceeds ${MAX_BIO_LENGTH} characters`, { method: 'saveUserProfile', }); } - updateUser.$set = updateUser.$set || {}; - updateUser.$set.bio = bio; + userUpdater.set('bio', bio); } else { - updateUser.$unset = updateUser.$unset || {}; - updateUser.$unset.bio = 1; + userUpdater.unset('bio'); } }; diff --git a/apps/meteor/app/lib/server/functions/saveUser/handleNickname.ts b/apps/meteor/app/lib/server/functions/saveUser/handleNickname.ts index 4a37ec9e1518..164f3933b126 100644 --- a/apps/meteor/app/lib/server/functions/saveUser/handleNickname.ts +++ b/apps/meteor/app/lib/server/functions/saveUser/handleNickname.ts @@ -1,22 +1,20 @@ import { MeteorError } from '@rocket.chat/core-services'; -import type { DeepPartial, DeepWritable, IUser } from '@rocket.chat/core-typings'; -import type { UpdateFilter } from 'mongodb'; +import type { IUser } from '@rocket.chat/core-typings'; +import type { Updater } from '@rocket.chat/model-typings'; import type { SaveUserData } from './saveUser'; const MAX_NICKNAME_LENGTH = 120; -export const handleNickname = (updateUser: DeepWritable>>, nickname: SaveUserData['nickname']) => { +export const handleNickname = (userUpdater: Updater, nickname: SaveUserData['nickname']) => { if (nickname?.trim()) { if (nickname.length > MAX_NICKNAME_LENGTH) { throw new MeteorError('error-nickname-size-exceeded', `Nickname size exceeds ${MAX_NICKNAME_LENGTH} characters`, { method: 'saveUserProfile', }); } - updateUser.$set = updateUser.$set || {}; - updateUser.$set.nickname = nickname; + userUpdater.set('nickname', nickname); } else { - updateUser.$unset = updateUser.$unset || {}; - updateUser.$unset.nickname = 1; + userUpdater.unset('nickname'); } }; diff --git a/apps/meteor/app/lib/server/functions/saveUser/saveNewUser.ts b/apps/meteor/app/lib/server/functions/saveUser/saveNewUser.ts index 18e2858e81c0..bb9a6a1cac67 100644 --- a/apps/meteor/app/lib/server/functions/saveUser/saveNewUser.ts +++ b/apps/meteor/app/lib/server/functions/saveUser/saveNewUser.ts @@ -1,7 +1,5 @@ -import type { DeepPartial, DeepWritable, IUser, RequiredField } from '@rocket.chat/core-typings'; import { Users } from '@rocket.chat/models'; import Gravatar from 'gravatar'; -import type { UpdateFilter } from 'mongodb'; import { getNewUserRoles } from '../../../../../server/services/user/lib/getNewUserRoles'; import { settings } from '../../../../settings/server'; @@ -34,25 +32,25 @@ export const saveNewUser = async function (userData: SaveUserData, sendPassword: const _id = await Accounts.createUserAsync(createUser); - const updateUser: RequiredField>>, '$set'> = { - $set: { - ...(typeof userData.name !== 'undefined' && { name: userData.name }), - settings: userData.settings || {}, - }, - }; + const updater = Users.getUpdater(); + + updater.set('settings', userData.settings || {}); + if (typeof userData.name !== 'undefined') { + updater.set('name', userData.name); + } if (typeof userData.requirePasswordChange !== 'undefined') { - updateUser.$set.requirePasswordChange = userData.requirePasswordChange; + updater.set('requirePasswordChange', userData.requirePasswordChange); } if (typeof userData.verified === 'boolean') { - updateUser.$set['emails.0.verified'] = userData.verified; + updater.set('emails.0.verified', userData.verified); } - handleBio(updateUser, userData.bio); - handleNickname(updateUser, userData.nickname); + handleBio(updater, userData.bio); + handleNickname(updater, userData.nickname); - await Users.updateOne({ _id }, updateUser as UpdateFilter); + await Users.updateFromUpdater({ _id }, updater); if (userData.sendWelcomeEmail) { await sendWelcomeEmail(userData); diff --git a/apps/meteor/app/lib/server/functions/saveUser/saveUser.ts b/apps/meteor/app/lib/server/functions/saveUser/saveUser.ts index ce9624c60444..307a0ac038a7 100644 --- a/apps/meteor/app/lib/server/functions/saveUser/saveUser.ts +++ b/apps/meteor/app/lib/server/functions/saveUser/saveUser.ts @@ -1,10 +1,9 @@ import { Apps, AppEvents } from '@rocket.chat/apps'; import { isUserFederated } from '@rocket.chat/core-typings'; -import type { DeepWritable, DeepPartial, IUser, IRole, IUserSettings, RequiredField } from '@rocket.chat/core-typings'; +import type { IUser, IRole, IUserSettings, RequiredField } from '@rocket.chat/core-typings'; import { Users } from '@rocket.chat/models'; import { Accounts } from 'meteor/accounts-base'; import { Meteor } from 'meteor/meteor'; -import type { UpdateFilter } from 'mongodb'; import { callbacks } from '../../../../../lib/callbacks'; import { hasPermissionAsync } from '../../../../authorization/server/functions/hasPermission'; @@ -46,6 +45,8 @@ export type SaveUserData = { joinDefaultChannels?: boolean; sendWelcomeEmail?: boolean; }; +export type UpdateUserData = RequiredField; +export const isUpdateUserData = (params: SaveUserData): params is UpdateUserData => '_id' in params && !!params._id; export const saveUser = async function (userId: IUser['_id'], userData: SaveUserData) { const oldUserData = userData._id && (await Users.findOneById(userData._id)); @@ -72,13 +73,15 @@ export const saveUser = async function (userId: IUser['_id'], userData: SaveUser delete userData.setRandomPassword; } - if (!userData._id) { + if (!isUpdateUserData(userData)) { return saveNewUser(userData, sendPassword); } - await validateUserEditing(userId, userData as RequiredField); + await validateUserEditing(userId, userData); // update user + const updater = Users.getUpdater(); + if (userData.hasOwnProperty('username') || userData.hasOwnProperty('name')) { if ( !(await saveUserIdentity({ @@ -86,6 +89,7 @@ export const saveUser = async function (userId: IUser['_id'], userData: SaveUser username: userData.username, name: userData.name, updateUsernameInBackground: true, + updater, })) ) { throw new Meteor.Error('error-could-not-save-identity', 'Could not save user identity', { @@ -95,12 +99,12 @@ export const saveUser = async function (userId: IUser['_id'], userData: SaveUser } if (typeof userData.statusText === 'string') { - await setStatusText(userData._id, userData.statusText); + await setStatusText(userData._id, userData.statusText, updater); } if (userData.email) { const shouldSendVerificationEmailToUser = userData.verified !== true; - await setEmail(userData._id, userData.email, shouldSendVerificationEmailToUser); + await setEmail(userData._id, userData.email, shouldSendVerificationEmailToUser, userData.verified === true, updater); } if ( @@ -113,37 +117,32 @@ export const saveUser = async function (userId: IUser['_id'], userData: SaveUser sendPassword = false; } - const updateUser: RequiredField>>, '$set' | '$unset'> = { - $set: {}, - $unset: {}, - }; - - handleBio(updateUser, userData.bio); - handleNickname(updateUser, userData.nickname); + handleBio(updater, userData.bio); + handleNickname(updater, userData.nickname); if (userData.roles) { - updateUser.$set.roles = userData.roles; + updater.set('roles', userData.roles); } if (userData.settings) { - updateUser.$set.settings = { preferences: userData.settings.preferences }; + updater.set('settings', { preferences: userData.settings.preferences }); } if (userData.language) { - updateUser.$set.language = userData.language; + updater.set('language', userData.language); } if (typeof userData.requirePasswordChange !== 'undefined') { - updateUser.$set.requirePasswordChange = userData.requirePasswordChange; + updater.set('requirePasswordChange', userData.requirePasswordChange); if (!userData.requirePasswordChange) { - updateUser.$unset.requirePasswordChangeReason = 1; + updater.unset('requirePasswordChangeReason'); } } - if (typeof userData.verified === 'boolean') { - updateUser.$set['emails.0.verified'] = userData.verified; + if (typeof userData.verified === 'boolean' && !userData.email) { + updater.set('emails.0.verified', userData.verified); } - await Users.updateOne({ _id: userData._id }, updateUser as UpdateFilter); + await Users.updateFromUpdater({ _id: userData._id }, updater); // App IPostUserUpdated event hook const userUpdated = await Users.findOneById(userData._id); diff --git a/apps/meteor/app/lib/server/functions/saveUser/validateUserData.ts b/apps/meteor/app/lib/server/functions/saveUser/validateUserData.ts index 52652a6c47b4..8e0df3c92999 100644 --- a/apps/meteor/app/lib/server/functions/saveUser/validateUserData.ts +++ b/apps/meteor/app/lib/server/functions/saveUser/validateUserData.ts @@ -10,6 +10,7 @@ import { settings } from '../../../../settings/server'; import { checkEmailAvailability } from '../checkEmailAvailability'; import { checkUsernameAvailability } from '../checkUsernameAvailability'; import type { SaveUserData } from './saveUser'; +import { isUpdateUserData } from './saveUser'; export const validateUserData = makeFunction(async (userId: IUser['_id'], userData: SaveUserData): Promise => { const existingRoles = await getRoleIds(); @@ -21,14 +22,14 @@ export const validateUserData = makeFunction(async (userId: IUser['_id'], userDa }); } - if (userData._id && userId !== userData._id && !(await hasPermissionAsync(userId, 'edit-other-user-info'))) { + if (isUpdateUserData(userData) && userId !== userData._id && !(await hasPermissionAsync(userId, 'edit-other-user-info'))) { throw new MeteorError('error-action-not-allowed', 'Editing user is not allowed', { method: 'insertOrUpdateUser', action: 'Editing_user', }); } - if (!userData._id && !(await hasPermissionAsync(userId, 'create-user'))) { + if (!isUpdateUserData(userData) && !(await hasPermissionAsync(userId, 'create-user'))) { throw new MeteorError('error-action-not-allowed', 'Adding user is not allowed', { method: 'insertOrUpdateUser', action: 'Adding_user', @@ -52,14 +53,14 @@ export const validateUserData = makeFunction(async (userId: IUser['_id'], userDa }); } - if (settings.get('Accounts_RequireNameForSignUp') && !userData._id && !trim(userData.name)) { + if (settings.get('Accounts_RequireNameForSignUp') && !isUpdateUserData(userData) && !trim(userData.name)) { throw new MeteorError('error-the-field-is-required', 'The field Name is required', { method: 'insertOrUpdateUser', field: 'Name', }); } - if (!userData._id && !trim(userData.username)) { + if (!isUpdateUserData(userData) && !trim(userData.username)) { throw new MeteorError('error-the-field-is-required', 'The field Username is required', { method: 'insertOrUpdateUser', field: 'Username', @@ -82,14 +83,14 @@ export const validateUserData = makeFunction(async (userId: IUser['_id'], userDa }); } - if (!userData._id && !userData.password && !userData.setRandomPassword) { + if (!isUpdateUserData(userData) && !userData.password && !userData.setRandomPassword) { throw new MeteorError('error-the-field-is-required', 'The field Password is required', { method: 'insertOrUpdateUser', field: 'Password', }); } - if (!userData._id) { + if (!isUpdateUserData(userData)) { if (userData.username && !(await checkUsernameAvailability(userData.username))) { throw new MeteorError('error-field-unavailable', `${escape(userData.username)} is already in use :(`, { method: 'insertOrUpdateUser', diff --git a/apps/meteor/app/lib/server/functions/saveUser/validateUserEditing.ts b/apps/meteor/app/lib/server/functions/saveUser/validateUserEditing.ts index fc151204fba1..582611399c40 100644 --- a/apps/meteor/app/lib/server/functions/saveUser/validateUserEditing.ts +++ b/apps/meteor/app/lib/server/functions/saveUser/validateUserEditing.ts @@ -1,8 +1,8 @@ import { MeteorError } from '@rocket.chat/core-services'; -import type { IUser, RequiredField } from '@rocket.chat/core-typings'; +import type { IUser } from '@rocket.chat/core-typings'; import { Users } from '@rocket.chat/models'; -import type { SaveUserData } from './saveUser'; +import type { UpdateUserData } from './saveUser'; import { hasPermissionAsync } from '../../../../authorization/server/functions/hasPermission'; import { settings } from '../../../../settings/server'; @@ -17,7 +17,7 @@ const isEditingField = (previousValue?: string, newValue?: string) => typeof new * @param {string} userId * @param {{ _id: string, roles?: string[], username?: string, name?: string, statusText?: string, email?: string, password?: string}} userData */ -export async function validateUserEditing(userId: IUser['_id'], userData: RequiredField): Promise { +export async function validateUserEditing(userId: IUser['_id'], userData: UpdateUserData): Promise { const editingMyself = userData._id && userId === userData._id; const canEditOtherUserInfo = await hasPermissionAsync(userId, 'edit-other-user-info'); diff --git a/apps/meteor/app/lib/server/functions/saveUserIdentity.ts b/apps/meteor/app/lib/server/functions/saveUserIdentity.ts index 7a200a029725..5f7aa27a427a 100644 --- a/apps/meteor/app/lib/server/functions/saveUserIdentity.ts +++ b/apps/meteor/app/lib/server/functions/saveUserIdentity.ts @@ -1,4 +1,5 @@ import type { IUser } from '@rocket.chat/core-typings'; +import type { Updater } from '@rocket.chat/models'; import { Messages, VideoConference, LivechatDepartmentAgents, Rooms, Subscriptions, Users } from '@rocket.chat/models'; import { _setRealName } from './setRealName'; @@ -23,11 +24,13 @@ export async function saveUserIdentity({ name: rawName, username: rawUsername, updateUsernameInBackground = false, + updater, }: { _id: string; name?: string; username?: string; updateUsernameInBackground?: boolean; // TODO: remove this + updater?: Updater; }) { if (!_id) { return false; @@ -51,14 +54,14 @@ export async function saveUserIdentity({ return false; } - if (!(await _setUsername(_id, username, user))) { + if (!(await _setUsername(_id, username, user, updater))) { return false; } user.username = username; } if (typeof rawName !== 'undefined' && nameChanged) { - if (!(await _setRealName(_id, name, user))) { + if (!(await _setRealName(_id, name, user, updater))) { return false; } } diff --git a/apps/meteor/app/lib/server/functions/setEmail.ts b/apps/meteor/app/lib/server/functions/setEmail.ts index 1ab42daf99e5..a2387efd1e66 100644 --- a/apps/meteor/app/lib/server/functions/setEmail.ts +++ b/apps/meteor/app/lib/server/functions/setEmail.ts @@ -1,3 +1,5 @@ +import type { IUser } from '@rocket.chat/core-typings'; +import type { Updater } from '@rocket.chat/models'; import { Users } from '@rocket.chat/models'; import { escapeHTML } from '@rocket.chat/string-helpers'; import { Meteor } from 'meteor/meteor'; @@ -37,7 +39,13 @@ const _sendEmailChangeNotification = async function (to: string, newEmail: strin } }; -const _setEmail = async function (userId: string, email: string, shouldSendVerificationEmail = true) { +const _setEmail = async function ( + userId: string, + email: string, + shouldSendVerificationEmail = true, + verified = false, + updater?: Updater, +) { email = email.trim(); if (!userId) { throw new Meteor.Error('error-invalid-user', 'Invalid user', { function: '_setEmail' }); @@ -74,7 +82,12 @@ const _setEmail = async function (userId: string, email: string, shouldSendVerif } // Set new email - await Users.setEmail(user?._id, email); + if (updater) { + updater.set('emails', [{ address: email, verified }]); + } else { + await Users.setEmail(user?._id, email, verified); + } + const result = { ...user, email, diff --git a/apps/meteor/app/lib/server/functions/setRealName.ts b/apps/meteor/app/lib/server/functions/setRealName.ts index 4ad08010fc81..e0138894357d 100644 --- a/apps/meteor/app/lib/server/functions/setRealName.ts +++ b/apps/meteor/app/lib/server/functions/setRealName.ts @@ -1,5 +1,6 @@ import { api } from '@rocket.chat/core-services'; import type { IUser } from '@rocket.chat/core-typings'; +import type { Updater } from '@rocket.chat/models'; import { Users } from '@rocket.chat/models'; import { Meteor } from 'meteor/meteor'; @@ -7,7 +8,12 @@ import { hasPermissionAsync } from '../../../authorization/server/functions/hasP import { settings } from '../../../settings/server'; import { RateLimiter } from '../lib'; -export const _setRealName = async function (userId: string, name: string, fullUser?: IUser): Promise { +export const _setRealName = async function ( + userId: string, + name: string, + fullUser?: IUser, + updater?: Updater, +): Promise { name = name.trim(); if (!userId || (settings.get('Accounts_RequireNameForSignUp') && !name)) { @@ -27,7 +33,13 @@ export const _setRealName = async function (userId: string, name: string, fullUs // Set new name if (name) { - await Users.setName(user._id, name); + if (updater) { + updater.set('name', name); + } else { + await Users.setName(user._id, name); + } + } else if (updater) { + updater.unset('name'); } else { await Users.unsetName(user._id); } diff --git a/apps/meteor/app/lib/server/functions/setStatusText.ts b/apps/meteor/app/lib/server/functions/setStatusText.ts index d55e5a8745d3..0184fde9070e 100644 --- a/apps/meteor/app/lib/server/functions/setStatusText.ts +++ b/apps/meteor/app/lib/server/functions/setStatusText.ts @@ -1,12 +1,13 @@ import { api } from '@rocket.chat/core-services'; import type { IUser } from '@rocket.chat/core-typings'; +import type { Updater } from '@rocket.chat/models'; import { Users } from '@rocket.chat/models'; import { Meteor } from 'meteor/meteor'; import { hasPermissionAsync } from '../../../authorization/server/functions/hasPermission'; import { RateLimiter } from '../lib'; -async function _setStatusTextPromise(userId: string, statusText: string): Promise { +async function _setStatusText(userId: string, statusText: string, updater?: Updater): Promise { if (!userId) { return false; } @@ -25,7 +26,11 @@ async function _setStatusTextPromise(userId: string, statusText: string): Promis return true; } - await Users.updateStatusText(user._id, statusText); + if (updater) { + updater.set('statusText', statusText); + } else { + await Users.updateStatusText(user._id, statusText); + } const { _id, username, status, name, roles } = user; void api.broadcast('presence.status', { @@ -36,17 +41,10 @@ async function _setStatusTextPromise(userId: string, statusText: string): Promis return true; } -export const setStatusText = RateLimiter.limitFunction( - async function _setStatusText(userId: any, statusText: string) { - return _setStatusTextPromise(userId, statusText); - }, - 5, - 60000, - { - async 0() { - // Administrators have permission to change others status, so don't limit those - const userId = Meteor.userId(); - return !userId || !(await hasPermissionAsync(userId, 'edit-other-user-info')); - }, +export const setStatusText = RateLimiter.limitFunction(_setStatusText, 5, 60000, { + async 0() { + // Administrators have permission to change others status, so don't limit those + const userId = Meteor.userId(); + return !userId || !(await hasPermissionAsync(userId, 'edit-other-user-info')); }, -); +}); diff --git a/apps/meteor/app/lib/server/functions/setUserAvatar.ts b/apps/meteor/app/lib/server/functions/setUserAvatar.ts index b7d545802b42..3b0f0406d6da 100644 --- a/apps/meteor/app/lib/server/functions/setUserAvatar.ts +++ b/apps/meteor/app/lib/server/functions/setUserAvatar.ts @@ -1,5 +1,6 @@ import { api } from '@rocket.chat/core-services'; import type { IUser } from '@rocket.chat/core-typings'; +import type { Updater } from '@rocket.chat/models'; import { Users } from '@rocket.chat/models'; import type { Response } from '@rocket.chat/server-fetch'; import { serverFetch as fetch } from '@rocket.chat/server-fetch'; @@ -66,6 +67,7 @@ export function setUserAvatar( contentType: string, service: 'rest', etag?: string, + updater?: Updater, ): Promise; export function setUserAvatar( user: Pick, @@ -73,6 +75,7 @@ export function setUserAvatar( contentType?: string, service?: 'initials' | 'url' | 'rest' | string, etag?: string, + updater?: Updater, ): Promise; export async function setUserAvatar( user: Pick, @@ -80,9 +83,14 @@ export async function setUserAvatar( contentType: string | undefined, service?: 'initials' | 'url' | 'rest' | string, etag?: string, + updater?: Updater, ): Promise { if (service === 'initials') { - await Users.setAvatarData(user._id, service, null); + if (updater) { + updater.set('avatarOrigin', origin); + } else { + await Users.setAvatarData(user._id, service, null); + } return; } @@ -177,7 +185,13 @@ export async function setUserAvatar( setTimeout(async () => { if (service) { - await Users.setAvatarData(user._id, service, avatarETag); + if (updater) { + updater.set('avatarOrigin', origin); + updater.set('avatarETag', avatarETag); + } else { + await Users.setAvatarData(user._id, service, avatarETag); + } + void api.broadcast('user.avatarUpdate', { username: user.username, avatarETag, diff --git a/apps/meteor/app/lib/server/functions/setUsername.ts b/apps/meteor/app/lib/server/functions/setUsername.ts index 57591d2ed2c9..6c63ecaee45c 100644 --- a/apps/meteor/app/lib/server/functions/setUsername.ts +++ b/apps/meteor/app/lib/server/functions/setUsername.ts @@ -1,5 +1,6 @@ import { api } from '@rocket.chat/core-services'; import type { IUser } from '@rocket.chat/core-typings'; +import type { Updater } from '@rocket.chat/models'; import { Invites, Users } from '@rocket.chat/models'; import { Accounts } from 'meteor/accounts-base'; import { Meteor } from 'meteor/meteor'; @@ -66,7 +67,7 @@ export const setUsernameWithValidation = async (userId: string, username: string void notifyOnUserChange({ clientAction: 'updated', id: user._id, diff: { username } }); }; -export const _setUsername = async function (userId: string, u: string, fullUser: IUser): Promise { +export const _setUsername = async function (userId: string, u: string, fullUser: IUser, updater?: Updater): Promise { const username = u.trim(); if (!userId || !username) { @@ -100,6 +101,7 @@ export const _setUsername = async function (userId: string, u: string, fullUser: SystemLogger.error(e); } // Set new username* + // TODO: use updater for setting the username and handle possible side effects in addUserToRoom await Users.setUsername(user._id, username); user.username = username; @@ -117,7 +119,7 @@ export const _setUsername = async function (userId: string, u: string, fullUser: } if (avatarData) { - await setUserAvatar(user, avatarData.blob, avatarData.contentType, serviceName); + await setUserAvatar(user, avatarData.blob, avatarData.contentType, serviceName, undefined, updater); } } diff --git a/apps/meteor/app/lib/server/lib/notifyListener.ts b/apps/meteor/app/lib/server/lib/notifyListener.ts index 6a28fabe5c51..0ff13deaf0d1 100644 --- a/apps/meteor/app/lib/server/lib/notifyListener.ts +++ b/apps/meteor/app/lib/server/lib/notifyListener.ts @@ -1,4 +1,4 @@ -import { api, dbWatchersDisabled } from '@rocket.chat/core-services'; +import { api } from '@rocket.chat/core-services'; import type { IRocketChatRecord, IRoom, @@ -24,6 +24,7 @@ import type { ILivechatContact, } from '@rocket.chat/core-typings'; import { + dbWatchersDisabled, Rooms, LivechatRooms, Permissions, diff --git a/apps/meteor/app/livechat/client/lib/stream/queueManager.ts b/apps/meteor/app/livechat/client/lib/stream/queueManager.ts index c6a671e2883d..4ebf49d55684 100644 --- a/apps/meteor/app/livechat/client/lib/stream/queueManager.ts +++ b/apps/meteor/app/livechat/client/lib/stream/queueManager.ts @@ -29,14 +29,14 @@ const events = { }; const invalidateRoomQueries = async (rid: string) => { - await queryClient.invalidateQueries(['rooms', { reference: rid, type: 'l' }]); - queryClient.removeQueries(['rooms', rid]); - queryClient.removeQueries(['/v1/rooms.info', rid]); + await queryClient.invalidateQueries({ queryKey: ['rooms', { reference: rid, type: 'l' }] }); + queryClient.removeQueries({ queryKey: ['rooms', rid] }); + queryClient.removeQueries({ queryKey: ['/v1/rooms.info', rid] }); }; const removeInquiry = async (inquiry: ILivechatInquiryRecord) => { LivechatInquiry.remove(inquiry._id); - return queryClient.invalidateQueries(['rooms', { reference: inquiry.rid, type: 'l' }]); + return queryClient.invalidateQueries({ queryKey: ['rooms', { reference: inquiry.rid, type: 'l' }] }); }; const getInquiriesFromAPI = async () => { diff --git a/apps/meteor/app/livechat/server/api/v1/videoCall.ts b/apps/meteor/app/livechat/server/api/v1/videoCall.ts index dd9c701e6495..01bda33724d1 100644 --- a/apps/meteor/app/livechat/server/api/v1/videoCall.ts +++ b/apps/meteor/app/livechat/server/api/v1/videoCall.ts @@ -46,7 +46,7 @@ API.v1.addRoute( let { callStatus } = room; if (!callStatus || callStatus === 'ended' || callStatus === 'declined') { - const { value } = await Settings.incrementValueById('WebRTC_Calls_Count', 1, { returnDocument: 'after' }); + const value = await Settings.incrementValueById('WebRTC_Calls_Count', 1, { returnDocument: 'after' }); if (value) { void notifyOnSettingChanged(value); } diff --git a/apps/meteor/app/livechat/server/lib/Helper.ts b/apps/meteor/app/livechat/server/lib/Helper.ts index 7eaf800a05df..b6a07024c989 100644 --- a/apps/meteor/app/livechat/server/lib/Helper.ts +++ b/apps/meteor/app/livechat/server/lib/Helper.ts @@ -72,7 +72,7 @@ export const createLivechatRoom = async ( guest: ILivechatVisitor, roomInfo: IOmnichannelRoomInfo = { source: { type: OmnichannelSourceType.OTHER } }, extraData?: IOmnichannelRoomExtraData, -) => { +): Promise => { check(rid, String); check( guest, @@ -157,14 +157,14 @@ export const createLivechatRoom = async ( }, ); - if (!result.value) { + if (!result) { throw new Error('Room not created'); } await callbacks.run('livechat.newRoom', room); await Message.saveSystemMessageAndNotifyUser('livechat-started', rid, '', { _id, username }, { groupable: false, token: guest.token }); - return result.value as IOmnichannelRoom; + return result as IOmnichannelRoom; }; export const createLivechatInquiry = async ({ @@ -239,11 +239,11 @@ export const createLivechatInquiry = async ({ ); logger.debug(`Inquiry ${result} created for visitor ${_id}`); - if (!result.value) { + if (!result) { throw new Error('Inquiry not created'); } - return result.value as ILivechatInquiryRecord; + return result; }; export const createLivechatSubscription = async ( diff --git a/apps/meteor/app/livechat/server/lib/Visitors.ts b/apps/meteor/app/livechat/server/lib/Visitors.ts index c7b4430df363..ccf4a13bd472 100644 --- a/apps/meteor/app/livechat/server/lib/Visitors.ts +++ b/apps/meteor/app/livechat/server/lib/Visitors.ts @@ -100,11 +100,11 @@ export const Visitors = { returnDocument: 'after', }); - if (!upsertedLivechatVisitor.value) { + if (!upsertedLivechatVisitor) { logger.debug(`No visitor found after upsert`); return null; } - return upsertedLivechatVisitor.value; + return upsertedLivechatVisitor; }, }; diff --git a/apps/meteor/app/livechat/server/lib/contacts/updateContact.ts b/apps/meteor/app/livechat/server/lib/contacts/updateContact.ts index 023568bd11de..6c344274386e 100644 --- a/apps/meteor/app/livechat/server/lib/contacts/updateContact.ts +++ b/apps/meteor/app/livechat/server/lib/contacts/updateContact.ts @@ -41,7 +41,7 @@ export async function updateContact(params: UpdateContactParams): Promise { - const { value } = await Settings.incrementValueById(data.settingsId, 1, { returnDocument: 'after' }); + const value = await Settings.incrementValueById(data.settingsId, 1, { returnDocument: 'after' }); if (value) { void notifyOnSettingChanged(value); } diff --git a/apps/meteor/app/ui-utils/client/lib/LegacyRoomManager.ts b/apps/meteor/app/ui-utils/client/lib/LegacyRoomManager.ts index bf33821de4a4..fa3445b6ad94 100644 --- a/apps/meteor/app/ui-utils/client/lib/LegacyRoomManager.ts +++ b/apps/meteor/app/ui-utils/client/lib/LegacyRoomManager.ts @@ -84,7 +84,7 @@ const computation = Tracker.autorun(() => { } Tracker.nonreactive(() => Object.entries(openedRooms).forEach(([typeName, record]) => { - if (record.active !== true || record.ready === true) { + if (record.active !== true || (record.ready === true && record.streamActive === true)) { return; } diff --git a/apps/meteor/app/utils/rocketchat.info b/apps/meteor/app/utils/rocketchat.info index f28db708eecb..c90634e2a51b 100644 --- a/apps/meteor/app/utils/rocketchat.info +++ b/apps/meteor/app/utils/rocketchat.info @@ -1,3 +1,3 @@ { - "version": "7.2.0-develop" + "version": "7.3.0-develop" } diff --git a/apps/meteor/client/NavBarV2/NavBarSettingsToolbar/UserMenu/hooks/useVoipItemsSection.tsx b/apps/meteor/client/NavBarV2/NavBarSettingsToolbar/UserMenu/hooks/useVoipItemsSection.tsx index 1ee34d14c8d5..9a2584869b13 100644 --- a/apps/meteor/client/NavBarV2/NavBarSettingsToolbar/UserMenu/hooks/useVoipItemsSection.tsx +++ b/apps/meteor/client/NavBarV2/NavBarSettingsToolbar/UserMenu/hooks/useVoipItemsSection.tsx @@ -40,12 +40,12 @@ export const useVoipItemsSection = (): { items: GenericMenuItemProps[] } | undef return t(clientError.message); } - if (!isReady || toggleVoip.isLoading) { + if (!isReady || toggleVoip.isPending) { return t('Loading'); } return ''; - }, [clientError, isReady, toggleVoip.isLoading, t]); + }, [clientError, isReady, toggleVoip.isPending, t]); return useMemo(() => { if (!isEnabled) { @@ -57,7 +57,7 @@ export const useVoipItemsSection = (): { items: GenericMenuItemProps[] } | undef { id: 'toggle-voip', icon: isRegistered ? 'phone-disabled' : 'phone', - disabled: !isReady || toggleVoip.isLoading, + disabled: !isReady || toggleVoip.isPending, onClick: () => toggleVoip.mutate(), content: ( diff --git a/apps/meteor/client/apps/gameCenter/GameCenter.tsx b/apps/meteor/client/apps/gameCenter/GameCenter.tsx index 768a9d9ec81e..56252008e9f5 100644 --- a/apps/meteor/client/apps/gameCenter/GameCenter.tsx +++ b/apps/meteor/client/apps/gameCenter/GameCenter.tsx @@ -1,5 +1,5 @@ import type { IExternalComponent } from '@rocket.chat/apps-engine/definition/externalComponent'; -import { useMutableCallback } from '@rocket.chat/fuselage-hooks'; +import { useEffectEvent } from '@rocket.chat/fuselage-hooks'; import { useState } from 'react'; import type { ReactElement } from 'react'; @@ -18,12 +18,12 @@ const GameCenter = (): ReactElement => { const result = useExternalComponentsQuery(); - const handleClose = useMutableCallback((e) => { + const handleClose = useEffectEvent((e) => { preventSyntheticEvent(e); closeTab(); }); - const handleBack = useMutableCallback((e) => { + const handleBack = useEffectEvent((e) => { setOpenedGame(undefined); preventSyntheticEvent(e); }); @@ -36,7 +36,7 @@ const GameCenter = (): ReactElement => { handleClose={handleClose} handleOpenGame={setOpenedGame} games={result.data} - isLoading={result.isLoading} + isLoading={result.isPending} /> )} diff --git a/apps/meteor/client/apps/gameCenter/GameCenterList.tsx b/apps/meteor/client/apps/gameCenter/GameCenterList.tsx index 32537f75a3cd..0318ab701c50 100644 --- a/apps/meteor/client/apps/gameCenter/GameCenterList.tsx +++ b/apps/meteor/client/apps/gameCenter/GameCenterList.tsx @@ -24,7 +24,7 @@ const GameCenterList = ({ handleClose, handleOpenGame, games, isLoading }: IGame const handleClose = (): void => { setModal(null); }; - setModal(() => ); + setModal(); }, [setModal], ); diff --git a/apps/meteor/client/apps/gameCenter/hooks/useExternalComponentsQuery.ts b/apps/meteor/client/apps/gameCenter/hooks/useExternalComponentsQuery.ts index 7089257a322a..ab09322aea3a 100644 --- a/apps/meteor/client/apps/gameCenter/hooks/useExternalComponentsQuery.ts +++ b/apps/meteor/client/apps/gameCenter/hooks/useExternalComponentsQuery.ts @@ -3,13 +3,13 @@ import { useQuery } from '@tanstack/react-query'; export const useExternalComponentsQuery = () => { const getExternalComponents = useEndpoint('GET', '/apps/externalComponents'); - return useQuery( - ['apps/external-components'], - async () => { + return useQuery({ + queryKey: ['apps/external-components'], + + queryFn: async () => { return (await getExternalComponents()).externalComponents; }, - { - staleTime: 10_000, - }, - ); + + staleTime: 10_000, + }); }; diff --git a/apps/meteor/client/components/CreateDiscussion/CreateDiscussion.tsx b/apps/meteor/client/components/CreateDiscussion/CreateDiscussion.tsx index cf633206cc1d..e7bdd852a67d 100644 --- a/apps/meteor/client/components/CreateDiscussion/CreateDiscussion.tsx +++ b/apps/meteor/client/components/CreateDiscussion/CreateDiscussion.tsx @@ -245,7 +245,7 @@ const CreateDiscussion = ({ onClose, defaultParentRoom, parentMessageId, nameSug - diff --git a/apps/meteor/client/components/CreateDiscussion/DefaultParentRoomField.tsx b/apps/meteor/client/components/CreateDiscussion/DefaultParentRoomField.tsx index cb3816f17abe..fd012f7c5f8a 100644 --- a/apps/meteor/client/components/CreateDiscussion/DefaultParentRoomField.tsx +++ b/apps/meteor/client/components/CreateDiscussion/DefaultParentRoomField.tsx @@ -18,11 +18,13 @@ const DefaultParentRoomField = ({ defaultParentRoom }: { defaultParentRoom: stri const roomsInfoEndpoint = useEndpoint('GET', '/v1/rooms.info'); - const { data, isLoading, isError } = useQuery(['defaultParentRoomInfo', query], async () => roomsInfoEndpoint(query), { + const { data, isPending, isError } = useQuery({ + queryKey: ['defaultParentRoomInfo', query], + queryFn: async () => roomsInfoEndpoint(query), refetchOnWindowFocus: false, }); - if (isLoading) { + if (isPending) { return ; } diff --git a/apps/meteor/client/components/Omnichannel/Tags.tsx b/apps/meteor/client/components/Omnichannel/Tags.tsx index 85d7f416037c..9a2a86500633 100644 --- a/apps/meteor/client/components/Omnichannel/Tags.tsx +++ b/apps/meteor/client/components/Omnichannel/Tags.tsx @@ -1,5 +1,5 @@ import { TextInput, Chip, Button, FieldLabel, FieldRow } from '@rocket.chat/fuselage'; -import { useMutableCallback } from '@rocket.chat/fuselage-hooks'; +import { useEffectEvent } from '@rocket.chat/fuselage-hooks'; import { useToastMessageDispatch } from '@rocket.chat/ui-contexts'; import type { ChangeEvent, ReactElement } from 'react'; import { useMemo, useState } from 'react'; @@ -20,7 +20,7 @@ type TagsProps = { const Tags = ({ tags = [], handler, error, tagRequired, department }: TagsProps): ReactElement => { const { t } = useTranslation(); - const { data: tagsResult, isInitialLoading } = useLivechatTags({ + const { data: tagsResult, isLoading } = useLivechatTags({ department, viewAll: !department, }); @@ -41,7 +41,7 @@ const Tags = ({ tags = [], handler, error, tagRequired, department }: TagsProps) handler(tags.filter((tag) => tag !== tagToRemove)); }; - const handleTagTextSubmit = useMutableCallback(() => { + const handleTagTextSubmit = useEffectEvent(() => { if (!tags) { return; } @@ -60,7 +60,7 @@ const Tags = ({ tags = [], handler, error, tagRequired, department }: TagsProps) handleTagValue(''); }); - if (isInitialLoading) { + if (isLoading) { return ; } diff --git a/apps/meteor/client/components/Omnichannel/hooks/useAgentsList.ts b/apps/meteor/client/components/Omnichannel/hooks/useAgentsList.ts index 630ba5f0116d..41dd4a485d92 100644 --- a/apps/meteor/client/components/Omnichannel/hooks/useAgentsList.ts +++ b/apps/meteor/client/components/Omnichannel/hooks/useAgentsList.ts @@ -37,7 +37,7 @@ export const useAgentsList = ( }, [options, reload]); const fetchData = useCallback( - async (start, end) => { + async (start: number, end: number) => { const { users: agents, total } = await getAgents({ ...(text && { text }), ...(excludeId && { excludeId }), diff --git a/apps/meteor/client/components/Omnichannel/hooks/useAvailableAgentsList.ts b/apps/meteor/client/components/Omnichannel/hooks/useAvailableAgentsList.ts index f0ee99e153cc..e56032e66292 100644 --- a/apps/meteor/client/components/Omnichannel/hooks/useAvailableAgentsList.ts +++ b/apps/meteor/client/components/Omnichannel/hooks/useAvailableAgentsList.ts @@ -29,7 +29,7 @@ export const useAvailableAgentsList = ( }, [options, reload]); const fetchData = useCallback( - async (start, end) => { + async (start: number, end: number) => { const { agents, total } = await getAgents({ ...(options.text && { text: options.text }), ...(options.includeExtension && { includeExtension: options.includeExtension }), diff --git a/apps/meteor/client/components/Omnichannel/hooks/useDepartmentsList.ts b/apps/meteor/client/components/Omnichannel/hooks/useDepartmentsList.ts index ac658e799ed6..58fa65e42809 100644 --- a/apps/meteor/client/components/Omnichannel/hooks/useDepartmentsList.ts +++ b/apps/meteor/client/components/Omnichannel/hooks/useDepartmentsList.ts @@ -40,7 +40,7 @@ export const useDepartmentsList = ( }, [options, reload]); const fetchData = useCallback( - async (start, end) => { + async (start: number, end: number) => { const { departments, total } = await getDepartments({ onlyMyDepartments: `${!!options.onlyMyDepartments}`, text: options.filter, diff --git a/apps/meteor/client/components/Omnichannel/hooks/useLivechatTags.ts b/apps/meteor/client/components/Omnichannel/hooks/useLivechatTags.ts index ce5704b66482..1b4aca036232 100644 --- a/apps/meteor/client/components/Omnichannel/hooks/useLivechatTags.ts +++ b/apps/meteor/client/components/Omnichannel/hooks/useLivechatTags.ts @@ -14,16 +14,16 @@ export const useLivechatTags = (options: Props) => { const { isEnterprise } = useOmnichannel(); const { department, text, viewAll } = options; - return useQuery( - ['/v1/livechat/tags', text, department], - () => + return useQuery({ + queryKey: ['/v1/livechat/tags', text, department], + + queryFn: () => getTags({ text: text || '', ...(department && { department }), viewAll: viewAll ? 'true' : 'false', }), - { - enabled: isEnterprise, - }, - ); + + enabled: isEnterprise, + }); }; diff --git a/apps/meteor/client/components/Omnichannel/modals/CloseChatModalData.tsx b/apps/meteor/client/components/Omnichannel/modals/CloseChatModalData.tsx index 867c992c8896..c1c6bb5e2446 100644 --- a/apps/meteor/client/components/Omnichannel/modals/CloseChatModalData.tsx +++ b/apps/meteor/client/components/Omnichannel/modals/CloseChatModalData.tsx @@ -21,9 +21,12 @@ const CloseChatModalData = ({ ) => Promise; }) => { const getDepartment = useEndpoint('GET', '/v1/livechat/department/:_id', { _id: departmentId }); - const { data, isLoading } = useQuery(['/v1/livechat/department/:_id', departmentId], () => getDepartment({})); + const { data, isPending } = useQuery({ + queryKey: ['/v1/livechat/department/:_id', departmentId], + queryFn: () => getDepartment({}), + }); - if (isLoading) { + if (isPending) { return ; } diff --git a/apps/meteor/client/components/Omnichannel/modals/ForwardChatModal.tsx b/apps/meteor/client/components/Omnichannel/modals/ForwardChatModal.tsx index bf85728cd0ee..b28339843817 100644 --- a/apps/meteor/client/components/Omnichannel/modals/ForwardChatModal.tsx +++ b/apps/meteor/client/components/Omnichannel/modals/ForwardChatModal.tsx @@ -24,16 +24,19 @@ import { AsyncStatePhase } from '../../../hooks/useAsyncState'; import AutoCompleteAgent from '../../AutoCompleteAgent'; import { useDepartmentsList } from '../hooks/useDepartmentsList'; -const ForwardChatModal = ({ - onForward, - onCancel, - room, - ...props -}: { +type ForwardChatModalFormData = { + comment: string; + department: string; + username: string; +}; + +type ForwardChatModalProps = { onForward: (departmentId?: string, userId?: string, comment?: string) => Promise; onCancel: () => void; room: IOmnichannelRoom; -}): ReactElement => { +}; + +const ForwardChatModal = ({ onForward, onCancel, room, ...props }: ForwardChatModalProps): ReactElement => { const { t } = useTranslation(); const getUserData = useEndpoint('GET', '/v1/users.info'); const idleAgentsAllowedForForwarding = useSetting('Livechat_enabled_when_agent_idle', true); @@ -46,7 +49,7 @@ const ForwardChatModal = ({ setValue, watch, formState: { isSubmitting }, - } = useForm(); + } = useForm(); useEffect(() => { setFocus('comment'); @@ -73,7 +76,7 @@ const ForwardChatModal = ({ ); const onSubmit = useCallback( - async ({ department: departmentId, username, comment }) => { + async ({ department: departmentId, username, comment }: ForwardChatModalFormData) => { let uid; if (username) { diff --git a/apps/meteor/client/components/RoomAutoComplete/RoomAutoComplete.tsx b/apps/meteor/client/components/RoomAutoComplete/RoomAutoComplete.tsx index 152fc6f9b7fe..66e30775ed79 100644 --- a/apps/meteor/client/components/RoomAutoComplete/RoomAutoComplete.tsx +++ b/apps/meteor/client/components/RoomAutoComplete/RoomAutoComplete.tsx @@ -3,7 +3,7 @@ import { AutoComplete, Option, Box } from '@rocket.chat/fuselage'; import { useDebouncedValue } from '@rocket.chat/fuselage-hooks'; import { RoomAvatar } from '@rocket.chat/ui-avatar'; import { useEndpoint } from '@rocket.chat/ui-contexts'; -import { useQuery } from '@tanstack/react-query'; +import { keepPreviousData, useQuery } from '@tanstack/react-query'; import type { ComponentProps, Dispatch, ReactElement, SetStateAction } from 'react'; import { memo, useMemo, useState } from 'react'; @@ -37,13 +37,11 @@ const RoomAutoComplete = ({ value, onChange, scope = 'regular', renderRoomIcon, const filterDebounced = useDebouncedValue(filter, 300); const roomsAutoCompleteEndpoint = useEndpoint('GET', ROOM_AUTOCOMPLETE_PARAMS[scope].endpoint); - const result = useQuery( - [ROOM_AUTOCOMPLETE_PARAMS[scope].key, filterDebounced], - () => roomsAutoCompleteEndpoint(generateQuery(filterDebounced)), - { - keepPreviousData: true, - }, - ); + const result = useQuery({ + queryKey: [ROOM_AUTOCOMPLETE_PARAMS[scope].key, filterDebounced], + queryFn: () => roomsAutoCompleteEndpoint(generateQuery(filterDebounced)), + placeholderData: keepPreviousData, + }); const options = useMemo( () => diff --git a/apps/meteor/client/components/RoomAutoCompleteMultiple/RoomAutoCompleteMultiple.tsx b/apps/meteor/client/components/RoomAutoCompleteMultiple/RoomAutoCompleteMultiple.tsx index 18c911402810..87ad4714cc00 100644 --- a/apps/meteor/client/components/RoomAutoCompleteMultiple/RoomAutoCompleteMultiple.tsx +++ b/apps/meteor/client/components/RoomAutoCompleteMultiple/RoomAutoCompleteMultiple.tsx @@ -2,7 +2,7 @@ import { AutoComplete, Option, Chip, Box, Skeleton } from '@rocket.chat/fuselage import { useDebouncedValue } from '@rocket.chat/fuselage-hooks'; import { RoomAvatar } from '@rocket.chat/ui-avatar'; import { useEndpoint } from '@rocket.chat/ui-contexts'; -import { useQuery } from '@tanstack/react-query'; +import { keepPreviousData, useQuery } from '@tanstack/react-query'; import type { ReactElement, ComponentProps } from 'react'; import { memo, useMemo, useState } from 'react'; @@ -21,8 +21,10 @@ const RoomAutoCompleteMultiple = ({ value, onChange, ...props }: RoomAutoComplet const filterDebounced = useDebouncedValue(filter, 300); const autocomplete = useEndpoint('GET', '/v1/rooms.autocomplete.channelAndPrivate'); - const result = useQuery(['rooms.autocomplete.channelAndPrivate', filterDebounced], () => autocomplete(generateQuery(filterDebounced)), { - keepPreviousData: true, + const result = useQuery({ + queryKey: ['rooms.autocomplete.channelAndPrivate', filterDebounced], + queryFn: () => autocomplete(generateQuery(filterDebounced)), + placeholderData: keepPreviousData, }); const options = useMemo( @@ -36,7 +38,7 @@ const RoomAutoCompleteMultiple = ({ value, onChange, ...props }: RoomAutoComplet [result.data?.items, result.isSuccess], ); - if (result.isLoading) { + if (result.isPending) { return ; } diff --git a/apps/meteor/client/components/UserAutoCompleteMultiple/UserAutoCompleteMultiple.tsx b/apps/meteor/client/components/UserAutoCompleteMultiple/UserAutoCompleteMultiple.tsx index 4ffb92ba2a51..d2d4a4774785 100644 --- a/apps/meteor/client/components/UserAutoCompleteMultiple/UserAutoCompleteMultiple.tsx +++ b/apps/meteor/client/components/UserAutoCompleteMultiple/UserAutoCompleteMultiple.tsx @@ -19,7 +19,10 @@ const UserAutoCompleteMultiple = ({ onChange, ...props }: UserAutoCompleteMultip const [filter, setFilter] = useState(''); const debouncedFilter = useDebouncedValue(filter, 1000); const usersAutoCompleteEndpoint = useEndpoint('GET', '/v1/users.autocomplete'); - const { data } = useQuery(['usersAutoComplete', debouncedFilter], async () => usersAutoCompleteEndpoint(query(debouncedFilter))); + const { data } = useQuery({ + queryKey: ['usersAutoComplete', debouncedFilter], + queryFn: async () => usersAutoCompleteEndpoint(query(debouncedFilter)), + }); const options = useMemo(() => data?.items.map((user) => ({ value: user.username, label: user.name })) || [], [data]); diff --git a/apps/meteor/client/components/UserAutoCompleteMultiple/UserAutoCompleteMultipleFederated.tsx b/apps/meteor/client/components/UserAutoCompleteMultiple/UserAutoCompleteMultipleFederated.tsx index 80bb67f12d66..6547fa02b9c9 100644 --- a/apps/meteor/client/components/UserAutoCompleteMultiple/UserAutoCompleteMultipleFederated.tsx +++ b/apps/meteor/client/components/UserAutoCompleteMultiple/UserAutoCompleteMultipleFederated.tsx @@ -2,7 +2,7 @@ import { MultiSelectFiltered, Icon, Box, Chip } from '@rocket.chat/fuselage'; import { useDebouncedValue } from '@rocket.chat/fuselage-hooks'; import { UserAvatar } from '@rocket.chat/ui-avatar'; import { useEndpoint } from '@rocket.chat/ui-contexts'; -import { useQuery } from '@tanstack/react-query'; +import { keepPreviousData, useQuery } from '@tanstack/react-query'; import type { ReactElement, AllHTMLAttributes } from 'react'; import { memo, useState, useCallback, useMemo } from 'react'; @@ -38,9 +38,10 @@ const UserAutoCompleteMultipleFederated = ({ const debouncedFilter = useDebouncedValue(filter, 500); const getUsers = useEndpoint('GET', '/v1/users.autocomplete'); - const { data } = useQuery( - ['users.autocomplete', debouncedFilter], - async () => { + const { data } = useQuery({ + queryKey: ['users.autocomplete', debouncedFilter], + + queryFn: async () => { const users = await getUsers({ selector: JSON.stringify({ term: debouncedFilter }) }); const options = users.items.map((item): [string, UserAutoCompleteOptionType] => [item.username, item]); @@ -52,8 +53,9 @@ const UserAutoCompleteMultipleFederated = ({ return options; }, - { keepPreviousData: true }, - ); + + placeholderData: keepPreviousData, + }); const options = useMemo(() => data || [], [data]); diff --git a/apps/meteor/client/components/avatar/RoomAvatarEditor.tsx b/apps/meteor/client/components/avatar/RoomAvatarEditor.tsx index 6692387f496a..91d0438d7302 100644 --- a/apps/meteor/client/components/avatar/RoomAvatarEditor.tsx +++ b/apps/meteor/client/components/avatar/RoomAvatarEditor.tsx @@ -2,7 +2,7 @@ import { isRoomFederated } from '@rocket.chat/core-typings'; import type { IRoom, RoomAdminFieldsType } from '@rocket.chat/core-typings'; import { css } from '@rocket.chat/css-in-js'; import { Box, Button, ButtonGroup } from '@rocket.chat/fuselage'; -import { useMutableCallback } from '@rocket.chat/fuselage-hooks'; +import { useEffectEvent } from '@rocket.chat/fuselage-hooks'; import { RoomAvatar } from '@rocket.chat/ui-avatar'; import { useToastMessageDispatch } from '@rocket.chat/ui-contexts'; import type { ReactElement } from 'react'; @@ -24,7 +24,7 @@ const RoomAvatarEditor = ({ disabled = false, room, roomAvatar, onChangeAvatar } const { t } = useTranslation(); const dispatchToastMessage = useToastMessageDispatch(); - const handleChangeAvatar = useMutableCallback(async (file) => { + const handleChangeAvatar = useEffectEvent(async (file) => { const reader = new FileReader(); reader.readAsDataURL(file); reader.onloadend = async (): Promise => { @@ -38,7 +38,7 @@ const RoomAvatarEditor = ({ disabled = false, room, roomAvatar, onChangeAvatar } }); const [clickUpload, reset] = useSingleFileInput(handleChangeAvatar); - const clickReset = useMutableCallback(() => { + const clickReset = useEffectEvent(() => { reset(); onChangeAvatar(null); }); diff --git a/apps/meteor/client/components/avatar/UserAvatarEditor/UserAvatarEditor.tsx b/apps/meteor/client/components/avatar/UserAvatarEditor/UserAvatarEditor.tsx index 1535446b1bd8..971b817b75f5 100644 --- a/apps/meteor/client/components/avatar/UserAvatarEditor/UserAvatarEditor.tsx +++ b/apps/meteor/client/components/avatar/UserAvatarEditor/UserAvatarEditor.tsx @@ -32,7 +32,7 @@ function UserAvatarEditor({ currentUsername, username, setAvatarObj, name, disab const dispatchToastMessage = useToastMessageDispatch(); const setUploadedPreview = useCallback( - async (file, avatarObj) => { + async (file: File, avatarObj: AvatarObject) => { setAvatarObj(avatarObj); try { const dataURL = await readFileAsDataURL(file); diff --git a/apps/meteor/client/components/message/MessageToolbarHolder.tsx b/apps/meteor/client/components/message/MessageToolbarHolder.tsx index e85c67096c81..e1b65b3d0dd7 100644 --- a/apps/meteor/client/components/message/MessageToolbarHolder.tsx +++ b/apps/meteor/client/components/message/MessageToolbarHolder.tsx @@ -22,9 +22,10 @@ const MessageToolbarHolder = ({ message, context }: MessageToolbarHolderProps): const showToolbar = isVisible || isToolbarMenuOpen; - const depsQueryResult = useQuery( - ['toolbox', message._id, context], - async () => { + const depsQueryResult = useQuery({ + queryKey: ['toolbox', message._id, context], + + queryFn: async () => { const room = await chat?.data.findRoom(); const subscription = await chat?.data.findSubscription(); return { @@ -32,10 +33,9 @@ const MessageToolbarHolder = ({ message, context }: MessageToolbarHolderProps): subscription, }; }, - { - enabled: showToolbar, - }, - ); + + enabled: showToolbar, + }); return ( diff --git a/apps/meteor/client/components/message/content/MessageActions.tsx b/apps/meteor/client/components/message/content/MessageActions.tsx index ee0042616f67..0433f796ea02 100644 --- a/apps/meteor/client/components/message/content/MessageActions.tsx +++ b/apps/meteor/client/components/message/content/MessageActions.tsx @@ -1,6 +1,6 @@ import type { IMessage } from '@rocket.chat/core-typings'; import { Box, ButtonGroup } from '@rocket.chat/fuselage'; -import { useMutableCallback } from '@rocket.chat/fuselage-hooks'; +import { useEffectEvent } from '@rocket.chat/fuselage-hooks'; import type { Keys as IconName } from '@rocket.chat/icons'; import type { TranslationKey } from '@rocket.chat/ui-contexts'; import type { ReactElement } from 'react'; @@ -23,7 +23,7 @@ type MessageActionsProps = { }; const MessageActions = ({ message, actions }: MessageActionsProps): ReactElement => { - const runAction = useMutableCallback((action: string) => () => { + const runAction = useEffectEvent((action: string) => () => { actionLinks.run(action, message); }); diff --git a/apps/meteor/client/components/message/content/attachments/default/ActionAttachmentButton.tsx b/apps/meteor/client/components/message/content/attachments/default/ActionAttachmentButton.tsx index 8491b2964f23..d0eddb046bce 100644 --- a/apps/meteor/client/components/message/content/attachments/default/ActionAttachmentButton.tsx +++ b/apps/meteor/client/components/message/content/attachments/default/ActionAttachmentButton.tsx @@ -28,7 +28,7 @@ const ActionAttachmentButton = ({ children, processingType, msg, mid }: ActionAt small value={msg} id={mid} - disabled={performActionMutation.isLoading} + disabled={performActionMutation.isPending} onClick={(event): void => { event.preventDefault(); diff --git a/apps/meteor/client/components/message/content/attachments/default/hooks/usePerformActionMutation.ts b/apps/meteor/client/components/message/content/attachments/default/hooks/usePerformActionMutation.ts index 82a757ae7187..807aa2727b3e 100644 --- a/apps/meteor/client/components/message/content/attachments/default/hooks/usePerformActionMutation.ts +++ b/apps/meteor/client/components/message/content/attachments/default/hooks/usePerformActionMutation.ts @@ -17,26 +17,30 @@ export const usePerformActionMutation = ( ): UseMutationResult => { const chat = useChat(); - return useMutation(async ({ processingType, msg, mid }) => { - if (!chat) { - return; - } - - switch (processingType) { - case 'sendMessage': - if (!msg) return; - await chat.flows.sendMessage({ text: msg }); + return useMutation({ + mutationFn: async ({ processingType, msg, mid }) => { + if (!chat) { return; - - case 'respondWithMessage': - if (!msg) return; - await chat.composer?.replyWith(msg); - return; - - case 'respondWithQuotedMessage': - if (!mid) return; - const message = await chat.data.getMessageByID(mid); - await chat.composer?.quoteMessage(message); - } - }, options); + } + + switch (processingType) { + case 'sendMessage': + if (!msg) return; + await chat.flows.sendMessage({ text: msg }); + return; + + case 'respondWithMessage': + if (!msg) return; + await chat.composer?.replyWith(msg); + return; + + case 'respondWithQuotedMessage': + if (!mid) return; + const message = await chat.data.getMessageByID(mid); + await chat.composer?.quoteMessage(message); + } + }, + + ...options, + }); }; diff --git a/apps/meteor/client/components/message/content/reactions/ReactionTooltip.tsx b/apps/meteor/client/components/message/content/reactions/ReactionTooltip.tsx index 13f13b838183..3d02999679e5 100644 --- a/apps/meteor/client/components/message/content/reactions/ReactionTooltip.tsx +++ b/apps/meteor/client/components/message/content/reactions/ReactionTooltip.tsx @@ -42,9 +42,10 @@ const ReactionTooltip = ({ emojiName, usernames, mine, messageId, showRealName, const getMessage = useGetMessageByID(); - const { data: users, isLoading } = useQuery( - ['chat.getMessage', 'reactions', messageId, usernames], - async () => { + const { data: users, isLoading } = useQuery({ + queryKey: ['chat.getMessage', 'reactions', messageId, usernames], + + queryFn: async () => { // This happens if the only reaction is from the current user if (!usernames.length) { return []; @@ -70,8 +71,9 @@ const ReactionTooltip = ({ emojiName, usernames, mine, messageId, showRealName, return reactions[emojiName].names || usernames; }, - { staleTime: 1000 * 60 * 5 }, - ); + + staleTime: 1000 * 60 * 5, + }); if (isLoading) { return ( diff --git a/apps/meteor/client/components/message/content/reactions/useToggleReactionMutation.ts b/apps/meteor/client/components/message/content/reactions/useToggleReactionMutation.ts index 9e9b3ca05599..52308f440630 100644 --- a/apps/meteor/client/components/message/content/reactions/useToggleReactionMutation.ts +++ b/apps/meteor/client/components/message/content/reactions/useToggleReactionMutation.ts @@ -14,11 +14,15 @@ export const useToggleReactionMutation = ( const uid = useUserId(); const reactToMessage = useEndpoint('POST', '/v1/chat.react'); - return useMutation(async ({ mid, reaction }) => { - if (!uid) { - throw new Error('Not logged in'); - } + return useMutation({ + mutationFn: async ({ mid, reaction }) => { + if (!uid) { + throw new Error('Not logged in'); + } - await reactToMessage({ messageId: mid, reaction }); - }, options); + await reactToMessage({ messageId: mid, reaction }); + }, + + ...options, + }); }; diff --git a/apps/meteor/client/components/message/hooks/usePinMessageMutation.ts b/apps/meteor/client/components/message/hooks/usePinMessageMutation.ts index 3405512dbe8b..6c59fb1f019f 100644 --- a/apps/meteor/client/components/message/hooks/usePinMessageMutation.ts +++ b/apps/meteor/client/components/message/hooks/usePinMessageMutation.ts @@ -26,7 +26,7 @@ export const usePinMessageMutation = () => { updatePinMessage(message, { pinned: false }); }, onSettled: (_data, _error, message) => { - queryClient.invalidateQueries(roomsQueryKeys.pinnedMessages(message.rid)); + queryClient.invalidateQueries({ queryKey: roomsQueryKeys.pinnedMessages(message.rid) }); }, }); }; diff --git a/apps/meteor/client/components/message/hooks/useStarMessageMutation.ts b/apps/meteor/client/components/message/hooks/useStarMessageMutation.ts index eabfc8692643..6454f60f1559 100644 --- a/apps/meteor/client/components/message/hooks/useStarMessageMutation.ts +++ b/apps/meteor/client/components/message/hooks/useStarMessageMutation.ts @@ -26,7 +26,7 @@ export const useStarMessageMutation = () => { dispatchToastMessage({ type: 'error', message: error }); }, onSettled: (_data, _error, message) => { - queryClient.invalidateQueries(roomsQueryKeys.starredMessages(message.rid)); + queryClient.invalidateQueries({ queryKey: roomsQueryKeys.starredMessages(message.rid) }); }, }); }; diff --git a/apps/meteor/client/components/message/hooks/useSubscriptionFromMessageQuery.ts b/apps/meteor/client/components/message/hooks/useSubscriptionFromMessageQuery.ts index 195032210e8d..8185f7cd7e44 100644 --- a/apps/meteor/client/components/message/hooks/useSubscriptionFromMessageQuery.ts +++ b/apps/meteor/client/components/message/hooks/useSubscriptionFromMessageQuery.ts @@ -6,7 +6,11 @@ import { useChat } from '../../../views/room/contexts/ChatContext'; export const useSubscriptionFromMessageQuery = (message: IMessage) => { const chat = useChat(); - return useQuery(['messages', message._id, 'subscription'], async () => { - return chat?.data.getSubscriptionFromMessage(message) ?? null; + return useQuery({ + queryKey: ['messages', message._id, 'subscription'], + + queryFn: async () => { + return chat?.data.getSubscriptionFromMessage(message) ?? null; + }, }); }; diff --git a/apps/meteor/client/components/message/hooks/useUnpinMessageMutation.ts b/apps/meteor/client/components/message/hooks/useUnpinMessageMutation.ts index f777929d5689..ed3880260dac 100644 --- a/apps/meteor/client/components/message/hooks/useUnpinMessageMutation.ts +++ b/apps/meteor/client/components/message/hooks/useUnpinMessageMutation.ts @@ -26,7 +26,7 @@ export const useUnpinMessageMutation = () => { updatePinMessage(message, { pinned: true }); }, onSettled: (_data, _error, message) => { - queryClient.invalidateQueries(roomsQueryKeys.pinnedMessages(message.rid)); + queryClient.invalidateQueries({ queryKey: roomsQueryKeys.pinnedMessages(message.rid) }); }, }); }; diff --git a/apps/meteor/client/components/message/hooks/useUnstarMessageMutation.ts b/apps/meteor/client/components/message/hooks/useUnstarMessageMutation.ts index 329e931fe116..353cd28d234c 100644 --- a/apps/meteor/client/components/message/hooks/useUnstarMessageMutation.ts +++ b/apps/meteor/client/components/message/hooks/useUnstarMessageMutation.ts @@ -26,7 +26,7 @@ export const useUnstarMessageMutation = () => { dispatchToastMessage({ type: 'error', message: error }); }, onSettled: (_data, _error, message) => { - queryClient.invalidateQueries(roomsQueryKeys.starredMessages(message.rid)); + queryClient.invalidateQueries({ queryKey: roomsQueryKeys.starredMessages(message.rid) }); }, }); }; diff --git a/apps/meteor/client/components/message/toolbar/useMessageActionAppsActionButtons.ts b/apps/meteor/client/components/message/toolbar/useMessageActionAppsActionButtons.ts index cecb79c183af..ba04cad4dfa5 100644 --- a/apps/meteor/client/components/message/toolbar/useMessageActionAppsActionButtons.ts +++ b/apps/meteor/client/components/message/toolbar/useMessageActionAppsActionButtons.ts @@ -1,7 +1,6 @@ import { type IUIActionButton, MessageActionContext as AppsEngineMessageActionContext } from '@rocket.chat/apps-engine/definition/ui'; import type { IMessage } from '@rocket.chat/core-typings'; import { useToastMessageDispatch } from '@rocket.chat/ui-contexts'; -import type { UseQueryResult } from '@tanstack/react-query'; import { useMemo } from 'react'; import { useTranslation } from 'react-i18next'; @@ -74,5 +73,5 @@ export const useMessageActionAppsActionButtons = (message: IMessage, context?: M return { ...result, data, - } as UseQueryResult; + }; }; diff --git a/apps/meteor/client/hooks/roomActions/useStartCallRoomAction/useVoipMenuOptions.tsx b/apps/meteor/client/hooks/roomActions/useStartCallRoomAction/useVoipMenuOptions.tsx index b1497dbfe4a6..28b955765c49 100644 --- a/apps/meteor/client/hooks/roomActions/useStartCallRoomAction/useVoipMenuOptions.tsx +++ b/apps/meteor/client/hooks/roomActions/useStartCallRoomAction/useVoipMenuOptions.tsx @@ -22,12 +22,12 @@ const useVoipMenuOptions = () => { const members = useMemo(() => uids.filter((uid) => uid !== ownUserId), [uids, ownUserId]); const remoteUserId = members[0]; - const { data: { user: remoteUser } = {}, isLoading } = useUserInfoQuery({ userId: remoteUserId }, { enabled: Boolean(remoteUserId) }); + const { data: { user: remoteUser } = {}, isPending } = useUserInfoQuery({ userId: remoteUserId }, { enabled: Boolean(remoteUserId) }); const isRemoteRegistered = !!remoteUser?.freeSwitchExtension; const isDM = members.length === 1; - const disabled = isMicPermissionDenied || !isDM || !isRemoteRegistered || !isRegistered || isInCall || isLoading; + const disabled = isMicPermissionDenied || !isDM || !isRemoteRegistered || !isRegistered || isInCall || isPending; const title = useMemo(() => { if (isMicPermissionDenied) { diff --git a/apps/meteor/client/hooks/useAppActionButtons.ts b/apps/meteor/client/hooks/useAppActionButtons.ts index b5796965b062..566baf69b37c 100644 --- a/apps/meteor/client/hooks/useAppActionButtons.ts +++ b/apps/meteor/client/hooks/useAppActionButtons.ts @@ -14,9 +14,12 @@ export const useAppActionButtons = const getActionButtons = useEndpoint('GET', '/apps/actionButtons'); - const result = useQuery(['apps', 'actionButtons'], () => getActionButtons(), { + const result = useQuery({ + queryKey: ['apps', 'actionButtons'], + queryFn: () => getActionButtons(), + ...(context && { - select: (data) => + select: (data: IUIActionButton[]) => data.filter( ( button, @@ -25,12 +28,15 @@ export const useAppActionButtons = } => button.context === context, ), }), + staleTime: Infinity, }); const invalidate = useDebouncedCallback( () => { - queryClient.invalidateQueries(['apps', 'actionButtons']); + queryClient.invalidateQueries({ + queryKey: ['apps', 'actionButtons'], + }); }, 100, [], diff --git a/apps/meteor/client/hooks/useAppSlashCommands.ts b/apps/meteor/client/hooks/useAppSlashCommands.ts index baa11ca00a69..3b3c45385cd6 100644 --- a/apps/meteor/client/hooks/useAppSlashCommands.ts +++ b/apps/meteor/client/hooks/useAppSlashCommands.ts @@ -14,7 +14,9 @@ export const useAppSlashCommands = () => { const invalidate = useDebouncedCallback( () => { - queryClient.invalidateQueries(['apps', 'slashCommands']); + queryClient.invalidateQueries({ + queryKey: ['apps', 'slashCommands'], + }); }, 100, [], @@ -36,9 +38,9 @@ export const useAppSlashCommands = () => { const getSlashCommands = useEndpoint('GET', '/v1/commands.list'); - useQuery( - ['apps', 'slashCommands'], - async () => { + const { data } = useQuery({ + queryKey: ['apps', 'slashCommands'] as const, + queryFn: async () => { let allCommands: Pick[] = []; let hasMore = true; let offset = 0; @@ -54,11 +56,14 @@ export const useAppSlashCommands = () => { return allCommands; }, - { - enabled: !!uid, - onSuccess(data) { - data.forEach((command) => slashCommands.add(command)); - }, - }, - ); + enabled: !!uid, + }); + + useEffect(() => { + if (!data) { + return; + } + + data.forEach((command) => slashCommands.add(command)); + }, [data]); }; diff --git a/apps/meteor/client/hooks/useClipboardWithToast.ts b/apps/meteor/client/hooks/useClipboardWithToast.ts index fd30e5989b54..ee8abc123744 100644 --- a/apps/meteor/client/hooks/useClipboardWithToast.ts +++ b/apps/meteor/client/hooks/useClipboardWithToast.ts @@ -1,5 +1,5 @@ import type { UseClipboardReturn } from '@rocket.chat/fuselage-hooks'; -import { useClipboard, useMutableCallback } from '@rocket.chat/fuselage-hooks'; +import { useClipboard, useEffectEvent } from '@rocket.chat/fuselage-hooks'; import { useToastMessageDispatch } from '@rocket.chat/ui-contexts'; import { useTranslation } from 'react-i18next'; @@ -8,7 +8,7 @@ export default function useClipboardWithToast(text: string): UseClipboardReturn const dispatchToastMessage = useToastMessageDispatch(); return useClipboard(text, { - onCopySuccess: useMutableCallback(() => dispatchToastMessage({ type: 'success', message: t('Copied') })), - onCopyError: useMutableCallback((e) => dispatchToastMessage({ type: 'error', message: e })), + onCopySuccess: useEffectEvent(() => dispatchToastMessage({ type: 'success', message: t('Copied') })), + onCopyError: useEffectEvent((e) => dispatchToastMessage({ type: 'error', message: e })), }); } diff --git a/apps/meteor/client/hooks/useEndpointAction.ts b/apps/meteor/client/hooks/useEndpointAction.ts index 4baf82a20ff2..96ed190f1588 100644 --- a/apps/meteor/client/hooks/useEndpointAction.ts +++ b/apps/meteor/client/hooks/useEndpointAction.ts @@ -21,7 +21,8 @@ export function useEndpointAction { if (options.successMessage) { dispatchToastMessage({ type: 'success', message: options.successMessage }); diff --git a/apps/meteor/client/hooks/useHighlightedCode.ts b/apps/meteor/client/hooks/useHighlightedCode.ts index e059bf3f1181..25036bb8b674 100644 --- a/apps/meteor/client/hooks/useHighlightedCode.ts +++ b/apps/meteor/client/hooks/useHighlightedCode.ts @@ -6,14 +6,18 @@ import hljs, { register } from '../../app/markdown/lib/hljs'; export function useHighlightedCode(language: string, text: string): string { const { t } = useTranslation(); - const { isLoading } = useQuery(['register-highlight-language', language], async () => { - try { - await register(language); - return true; - } catch (error) { - console.error('Not possible to register the provided language'); - } + const { isPending } = useQuery({ + queryKey: ['register-highlight-language', language], + + queryFn: async () => { + try { + await register(language); + return true; + } catch (error) { + console.error('Not possible to register the provided language'); + } + }, }); - return useMemo(() => (isLoading ? t('Loading') : hljs.highlight(language, text).value), [isLoading, language, text, t]); + return useMemo(() => (isPending ? t('Loading') : hljs.highlight(language, text).value), [isPending, language, text, t]); } diff --git a/apps/meteor/client/hooks/useLicense.ts b/apps/meteor/client/hooks/useLicense.ts index 6c50ff55fe74..c6f0c96a37dd 100644 --- a/apps/meteor/client/hooks/useLicense.ts +++ b/apps/meteor/client/hooks/useLicense.ts @@ -2,7 +2,7 @@ import type { Serialized } from '@rocket.chat/core-typings'; import type { OperationResult } from '@rocket.chat/rest-typings'; import { useEndpoint, useStream, useUserId } from '@rocket.chat/ui-contexts'; import type { QueryClient, UseQueryResult } from '@tanstack/react-query'; -import { useQuery, useQueryClient } from '@tanstack/react-query'; +import { keepPreviousData, useQuery, useQueryClient } from '@tanstack/react-query'; import { useEffect } from 'react'; type LicenseDataType = Serialized>>; @@ -18,7 +18,9 @@ const invalidateQueryClientLicenses = (() => { clearTimeout(timeout); timeout = setTimeout(() => { timeout = undefined; - queryClient.invalidateQueries(['licenses']); + queryClient.invalidateQueries({ + queryKey: ['licenses'], + }); }, milliseconds); }; })(); @@ -40,9 +42,11 @@ export const useLicenseBase = ({ useEffect(() => notify('license', () => invalidateQueries()), [notify, invalidateQueries]); - return useQuery(['licenses', 'getLicenses', params], () => getLicenses({ ...params }), { + return useQuery({ + queryKey: ['licenses', 'getLicenses', params], + queryFn: () => getLicenses({ ...params }), staleTime: Infinity, - keepPreviousData: true, + placeholderData: keepPreviousData, select, enabled: !!uid, }); diff --git a/apps/meteor/client/hooks/useLicenseLimitsByBehavior.ts b/apps/meteor/client/hooks/useLicenseLimitsByBehavior.ts index ba7e165496ea..46b86c732833 100644 --- a/apps/meteor/client/hooks/useLicenseLimitsByBehavior.ts +++ b/apps/meteor/client/hooks/useLicenseLimitsByBehavior.ts @@ -8,7 +8,7 @@ type LicenseLimitsByBehavior = Record; export const useLicenseLimitsByBehavior = () => { const result = useLicense({ loadValues: true }); - if (result.isLoading || result.isError) { + if (result.isPending || result.isError) { return null; } diff --git a/apps/meteor/client/hooks/useMessageboxAppsActionButtons.ts b/apps/meteor/client/hooks/useMessageboxAppsActionButtons.ts index 10c6f4f58ef4..2e2ab4b21ab9 100644 --- a/apps/meteor/client/hooks/useMessageboxAppsActionButtons.ts +++ b/apps/meteor/client/hooks/useMessageboxAppsActionButtons.ts @@ -1,5 +1,4 @@ import { useToastMessageDispatch } from '@rocket.chat/ui-contexts'; -import type { UseQueryResult } from '@tanstack/react-query'; import { useMemo } from 'react'; import { useTranslation } from 'react-i18next'; @@ -10,7 +9,7 @@ import type { MessageBoxAction } from '../../app/ui-utils/client/lib/messageBox' import { Utilities } from '../../ee/lib/misc/Utilities'; import { useUiKitActionManager } from '../uikit/hooks/useUiKitActionManager'; -export const useMessageboxAppsActionButtons = (): UseQueryResult => { +export const useMessageboxAppsActionButtons = () => { const result = useAppActionButtons('messageBoxAction'); const actionManager = useUiKitActionManager(); const dispatchToastMessage = useToastMessageDispatch(); @@ -52,11 +51,12 @@ export const useMessageboxAppsActionButtons = (): UseQueryResult; + }; }; diff --git a/apps/meteor/client/hooks/useReactiveQuery.ts b/apps/meteor/client/hooks/useReactiveQuery.ts index 61bffde48c26..9737e74f64e8 100644 --- a/apps/meteor/client/hooks/useReactiveQuery.ts +++ b/apps/meteor/client/hooks/useReactiveQuery.ts @@ -28,7 +28,7 @@ export const useReactiveQuery = { const getRegistrationStatus = useEndpoint('GET', '/v1/cloud.registrationStatus'); const canViewregistrationStatus = usePermission('manage-cloud'); - const queryResult = useQuery( - ['getRegistrationStatus'], - () => { + const queryResult = useQuery({ + queryKey: ['getRegistrationStatus'], + queryFn: () => { if (!canViewregistrationStatus) { throw new Error('unauthorized api call'); } return getRegistrationStatus(); }, - { - keepPreviousData: true, - staleTime: Infinity, - }, - ); + staleTime: Infinity, + }); - return { isRegistered: !queryResult.isLoading && queryResult.data?.registrationStatus?.workspaceRegistered, ...queryResult }; + return { isRegistered: !queryResult.isPending && queryResult.data?.registrationStatus?.workspaceRegistered, ...queryResult }; }; diff --git a/apps/meteor/client/hooks/useRoomInfoEndpoint.ts b/apps/meteor/client/hooks/useRoomInfoEndpoint.ts index 0bac1d7eb413..fbce560fd327 100644 --- a/apps/meteor/client/hooks/useRoomInfoEndpoint.ts +++ b/apps/meteor/client/hooks/useRoomInfoEndpoint.ts @@ -9,15 +9,19 @@ import type { Meteor } from 'meteor/meteor'; export const useRoomInfoEndpoint = (rid: IRoom['_id']): UseQueryResult> => { const getRoomInfo = useEndpoint('GET', '/v1/rooms.info'); const uid = useUserId(); - return useQuery(['/v1/rooms.info', rid], () => getRoomInfo({ roomId: rid }), { - cacheTime: minutesToMilliseconds(15), + return useQuery({ + queryKey: ['/v1/rooms.info', rid], + queryFn: () => getRoomInfo({ roomId: rid }), + gcTime: minutesToMilliseconds(15), staleTime: minutesToMilliseconds(5), + retry: (count, error: Meteor.Error) => { if (count > 2 || error.error === 'not-allowed') { return false; } return true; }, + enabled: !!uid, }); }; diff --git a/apps/meteor/client/hooks/useRoomsList.ts b/apps/meteor/client/hooks/useRoomsList.ts index 66582d3b62f2..6dfed72f6eee 100644 --- a/apps/meteor/client/hooks/useRoomsList.ts +++ b/apps/meteor/client/hooks/useRoomsList.ts @@ -33,7 +33,7 @@ export const useRoomsList = ( }, [options, reload]); const fetchData = useCallback( - async (start, end) => { + async (start: number, end: number) => { const { items: rooms, total } = await getRooms({ selector: JSON.stringify({ name: options.text || '' }), offset: start, diff --git a/apps/meteor/client/hooks/useSingleFileInput.ts b/apps/meteor/client/hooks/useSingleFileInput.ts index 3ecdb14e7226..629152008d01 100644 --- a/apps/meteor/client/hooks/useSingleFileInput.ts +++ b/apps/meteor/client/hooks/useSingleFileInput.ts @@ -1,4 +1,4 @@ -import { useMutableCallback } from '@rocket.chat/fuselage-hooks'; +import { useEffectEvent } from '@rocket.chat/fuselage-hooks'; import { useRef, useEffect } from 'react'; export const useSingleFileInput = ( @@ -52,8 +52,8 @@ export const useSingleFileInput = ( }; }, [fileField, fileType, onSetFile]); - const onClick = useMutableCallback(() => ref?.current?.click()); - const reset = useMutableCallback(() => { + const onClick = useEffectEvent(() => ref?.current?.click()); + const reset = useEffectEvent(() => { if (ref.current) { ref.current.value = ''; } diff --git a/apps/meteor/client/hooks/useTagsList.ts b/apps/meteor/client/hooks/useTagsList.ts index 9ca827331d42..5857193b9677 100644 --- a/apps/meteor/client/hooks/useTagsList.ts +++ b/apps/meteor/client/hooks/useTagsList.ts @@ -32,7 +32,7 @@ export const useTagsList = (options: TagsListOptions): UseTagsListResult => { }, [options, reload]); const fetchData = useCallback( - async (start, end) => { + async (start: number, end: number) => { const { tags, total } = await getTags({ text: filter, offset: start, diff --git a/apps/meteor/client/hooks/useTranslationsForApps.ts b/apps/meteor/client/hooks/useTranslationsForApps.ts index 56e29c24a193..c1a4cd3fad54 100644 --- a/apps/meteor/client/hooks/useTranslationsForApps.ts +++ b/apps/meteor/client/hooks/useTranslationsForApps.ts @@ -41,7 +41,9 @@ export const useTranslationsForApps = () => { } const invalidate = withDebouncing({ wait: 100 })(() => { - queryClient.invalidateQueries(['apps', 'translations']); + queryClient.invalidateQueries({ + queryKey: ['apps', 'translations'], + }); }); const unsubscribe = subscribeToApps('apps', ([key]) => { diff --git a/apps/meteor/client/hooks/useUserDropdownAppsActionButtons.ts b/apps/meteor/client/hooks/useUserDropdownAppsActionButtons.ts index 69355590fe90..eb1f5a3823ff 100644 --- a/apps/meteor/client/hooks/useUserDropdownAppsActionButtons.ts +++ b/apps/meteor/client/hooks/useUserDropdownAppsActionButtons.ts @@ -21,7 +21,7 @@ export const useUserDropdownAppsActionButtons = () => { () => result.data ?.filter((action) => applyButtonFilters(action)) - .map((action) => { + .map((action): GenericMenuItemProps => { return { id: `${action.appId}_${action.actionId}`, // icon: action.icon as GenericMenuItemProps['icon'], @@ -52,5 +52,5 @@ export const useUserDropdownAppsActionButtons = () => { return { ...result, data, - } as UseQueryResult; + } as unknown as UseQueryResult; }; diff --git a/apps/meteor/client/hooks/useUserInfoQuery.ts b/apps/meteor/client/hooks/useUserInfoQuery.ts index fdbe793d60e3..371921087a5e 100644 --- a/apps/meteor/client/hooks/useUserInfoQuery.ts +++ b/apps/meteor/client/hooks/useUserInfoQuery.ts @@ -1,14 +1,18 @@ import type { UsersInfoParamsGet } from '@rocket.chat/rest-typings'; import { useEndpoint } from '@rocket.chat/ui-contexts'; -import { useQuery } from '@tanstack/react-query'; +import { keepPreviousData, useQuery } from '@tanstack/react-query'; type UserInfoQueryOptions = { enabled?: boolean; - keepPreviousData?: boolean; + placeholderData?: (previousData: T | undefined) => T | undefined; }; // a hook using tanstack useQuery and useEndpoint that fetches user information from the `users.info` endpoint -export const useUserInfoQuery = (params: UsersInfoParamsGet, options: UserInfoQueryOptions = { keepPreviousData: true }) => { +export const useUserInfoQuery = (params: UsersInfoParamsGet, options: UserInfoQueryOptions = { placeholderData: keepPreviousData }) => { const getUserInfo = useEndpoint('GET', '/v1/users.info'); - return useQuery(['users.info', params], () => getUserInfo({ ...params }), options); + return useQuery({ + queryKey: ['users.info', params], + queryFn: () => getUserInfo({ ...params }), + ...options, + }); }; diff --git a/apps/meteor/client/hooks/useWorkspaceInfo.ts b/apps/meteor/client/hooks/useWorkspaceInfo.ts index fbc9ba872556..e5efd1f6a508 100644 --- a/apps/meteor/client/hooks/useWorkspaceInfo.ts +++ b/apps/meteor/client/hooks/useWorkspaceInfo.ts @@ -1,7 +1,7 @@ import type { IStats, IWorkspaceInfo, Serialized } from '@rocket.chat/core-typings'; import type { IInstance } from '@rocket.chat/rest-typings'; import { useEndpoint } from '@rocket.chat/ui-contexts'; -import { useMutation, useQueries, useQueryClient } from '@tanstack/react-query'; +import { keepPreviousData, useMutation, useQueries, useQueryClient } from '@tanstack/react-query'; export const useWorkspaceInfo = ({ refreshStatistics }: { refreshStatistics?: boolean } = {}) => { const getStatistics = useEndpoint('GET', '/v1/statistics'); @@ -28,14 +28,15 @@ export const useWorkspaceInfo = ({ refreshStatistics }: { refreshStatistics?: bo return data as IWorkspaceInfo; }, staleTime: Infinity, - keepPreviousData: true, + placeholderData: keepPreviousData, }, { queryKey: ['info', 'instances'], queryFn: () => getInstances(), staleTime: Infinity, - keepPreviousData: true, - select({ instances }: Serialized<{ instances: IInstance[] }>) { + placeholderData: keepPreviousData, + select(data: unknown) { + const { instances } = data as Serialized<{ instances: IInstance[] }>; return instances.map((instance) => ({ ...instance, ...(instance.instanceRecord && { @@ -51,11 +52,14 @@ export const useWorkspaceInfo = ({ refreshStatistics }: { refreshStatistics?: bo queryKey: ['info', 'statistics'], queryFn: () => getStatistics({ refresh: refreshStatistics ? 'true' : 'false' }), staleTime: Infinity, - keepPreviousData: true, - select: (data: Serialized) => ({ - ...data, - lastMessageSentAt: data.lastMessageSentAt ? new Date(data.lastMessageSentAt) : undefined, - }), + placeholderData: keepPreviousData, + select: (data: unknown) => { + const statsData = data as Serialized; + return { + ...statsData, + lastMessageSentAt: statsData.lastMessageSentAt ? new Date(statsData.lastMessageSentAt) : undefined, + }; + }, }, ], }); @@ -64,6 +68,9 @@ export const useWorkspaceInfo = ({ refreshStatistics }: { refreshStatistics?: bo export const useRefreshStatistics = () => { const queryClient = useQueryClient(); return useMutation({ - mutationFn: () => queryClient.invalidateQueries(['info', 'statistics']), + mutationFn: () => + queryClient.invalidateQueries({ + queryKey: ['info', 'statistics'], + }), }); }; diff --git a/apps/meteor/client/hooks/webdav/useWebDAVAccountIntegrationsQuery.ts b/apps/meteor/client/hooks/webdav/useWebDAVAccountIntegrationsQuery.ts index 171490b33d18..3381e03abf5f 100644 --- a/apps/meteor/client/hooks/webdav/useWebDAVAccountIntegrationsQuery.ts +++ b/apps/meteor/client/hooks/webdav/useWebDAVAccountIntegrationsQuery.ts @@ -39,7 +39,7 @@ export const useWebDAVAccountIntegrationsQuery = ({ enabled = true, ...options } return subscribeToNotifyUser(`${uid}/webdav`, ({ type, account }) => { switch (type) { case 'changed': - queryClient.invalidateQueries(queryKey); + queryClient.invalidateQueries({ queryKey }); break; case 'removed': diff --git a/apps/meteor/client/lib/queryClient.ts b/apps/meteor/client/lib/queryClient.ts index 2bb38d001242..f24351738f9c 100644 --- a/apps/meteor/client/lib/queryClient.ts +++ b/apps/meteor/client/lib/queryClient.ts @@ -3,7 +3,6 @@ import { QueryClient } from '@tanstack/react-query'; export const queryClient = new QueryClient({ defaultOptions: { queries: { - onError: console.warn, refetchOnWindowFocus: false, retry: process.env.TEST_MODE === 'true', }, diff --git a/apps/meteor/client/navbar/actions/NavbarHomeAction.tsx b/apps/meteor/client/navbar/actions/NavbarHomeAction.tsx index 420d1f3fd83a..ec9a18464224 100644 --- a/apps/meteor/client/navbar/actions/NavbarHomeAction.tsx +++ b/apps/meteor/client/navbar/actions/NavbarHomeAction.tsx @@ -1,5 +1,5 @@ import { IconButton } from '@rocket.chat/fuselage'; -import { useMutableCallback } from '@rocket.chat/fuselage-hooks'; +import { useEffectEvent } from '@rocket.chat/fuselage-hooks'; import { useRouter, useLayout, useSetting } from '@rocket.chat/ui-contexts'; import type { HTMLAttributes } from 'react'; import { useTranslation } from 'react-i18next'; @@ -16,7 +16,7 @@ const NavbarHomeAction = (props: NavbarHomeActionProps) => { const routeName = router.getLocationPathname(); - const handleHome = useMutableCallback(() => { + const handleHome = useEffectEvent(() => { sidebar.toggle(); router.navigate('/home'); }); diff --git a/apps/meteor/client/omnichannel/additionalForms/DepartmentBusinessHours.tsx b/apps/meteor/client/omnichannel/additionalForms/DepartmentBusinessHours.tsx index aa8a34889245..1d40dc116c74 100644 --- a/apps/meteor/client/omnichannel/additionalForms/DepartmentBusinessHours.tsx +++ b/apps/meteor/client/omnichannel/additionalForms/DepartmentBusinessHours.tsx @@ -9,7 +9,10 @@ export const DepartmentBusinessHours = ({ bhId }: { bhId: string | undefined }) const { t } = useTranslation(); const hasLicense = useHasLicenseModule('livechat-enterprise'); const getBusinessHour = useEndpoint('GET', '/v1/livechat/business-hour'); - const { data } = useQuery(['/v1/livechat/business-hour', bhId], () => getBusinessHour({ _id: bhId, type: 'custom' })); + const { data } = useQuery({ + queryKey: ['/v1/livechat/business-hour', bhId], + queryFn: () => getBusinessHour({ _id: bhId, type: 'custom' }), + }); const name = data?.businessHour?.name; diff --git a/apps/meteor/client/omnichannel/businessHours/BusinessHoursTable.tsx b/apps/meteor/client/omnichannel/businessHours/BusinessHoursTable.tsx index 62937dbc4005..01c5d64abad6 100644 --- a/apps/meteor/client/omnichannel/businessHours/BusinessHoursTable.tsx +++ b/apps/meteor/client/omnichannel/businessHours/BusinessHoursTable.tsx @@ -35,9 +35,11 @@ const BusinessHoursTable = () => { ); const getBusinessHours = useEndpoint('GET', '/v1/livechat/business-hours'); - const { data, isLoading, isSuccess, isError, refetch } = useQuery(['livechat-getBusinessHours', query], async () => - getBusinessHours(query), - ); + const { data, isLoading, isSuccess, isError, refetch } = useQuery({ + queryKey: ['livechat-getBusinessHours', query], + + queryFn: async () => getBusinessHours(query), + }); const headers = ( <> diff --git a/apps/meteor/client/omnichannel/businessHours/useRemoveBusinessHour.tsx b/apps/meteor/client/omnichannel/businessHours/useRemoveBusinessHour.tsx index 27ae0c6c4e29..3bb9fde92d0e 100644 --- a/apps/meteor/client/omnichannel/businessHours/useRemoveBusinessHour.tsx +++ b/apps/meteor/client/omnichannel/businessHours/useRemoveBusinessHour.tsx @@ -1,4 +1,4 @@ -import { useMutableCallback } from '@rocket.chat/fuselage-hooks'; +import { useEffectEvent } from '@rocket.chat/fuselage-hooks'; import { useSetModal, useToastMessageDispatch, useMethod } from '@rocket.chat/ui-contexts'; import { useQueryClient } from '@tanstack/react-query'; import { useTranslation } from 'react-i18next'; @@ -12,12 +12,14 @@ export const useRemoveBusinessHour = () => { const removeBusinessHour = useMethod('livechat:removeBusinessHour'); const queryClient = useQueryClient(); - const handleRemove = useMutableCallback((_id, type) => { + const handleRemove = useEffectEvent((_id, type) => { const onDeleteBusinessHour = async () => { try { await removeBusinessHour(_id, type); dispatchToastMessage({ type: 'success', message: t('Business_Hour_Removed') }); - queryClient.invalidateQueries(['livechat-getBusinessHours']); + queryClient.invalidateQueries({ + queryKey: ['livechat-getBusinessHours'], + }); } catch (error) { dispatchToastMessage({ type: 'error', message: error }); } finally { diff --git a/apps/meteor/client/omnichannel/cannedResponses/CannedResponseEdit.tsx b/apps/meteor/client/omnichannel/cannedResponses/CannedResponseEdit.tsx index 7fc1ee18f9e0..b4b0ef40ba99 100644 --- a/apps/meteor/client/omnichannel/cannedResponses/CannedResponseEdit.tsx +++ b/apps/meteor/client/omnichannel/cannedResponses/CannedResponseEdit.tsx @@ -10,6 +10,15 @@ import CannedResponseForm from './components/cannedResponseForm'; import { useRemoveCannedResponse } from './useRemoveCannedResponse'; import { Page, PageHeader, PageScrollableContentWithShadow, PageFooter } from '../../components/Page'; +type CannedResponseEditFormData = { + _id: string; + shortcut: string; + text: string; + tags: string[]; + scope: string; + departmentId: string; +}; + type CannedResponseEditProps = { cannedResponseData?: Serialized; departmentData?: Serialized; @@ -32,7 +41,7 @@ const CannedResponseEdit = ({ cannedResponseData }: CannedResponseEditProps) => const saveCannedResponse = useEndpoint('POST', '/v1/canned-responses'); - const methods = useForm({ defaultValues: getInitialData(cannedResponseData) }); + const methods = useForm({ defaultValues: getInitialData(cannedResponseData) }); const { handleSubmit, @@ -43,10 +52,9 @@ const CannedResponseEdit = ({ cannedResponseData }: CannedResponseEditProps) => const handleDelete = useRemoveCannedResponse(); const handleSave = useCallback( - async ({ departmentId, ...data }) => { + async ({ departmentId, ...data }: CannedResponseEditFormData) => { try { await saveCannedResponse({ - _id: cannedResponseData?._id, ...data, ...(departmentId && { departmentId }), }); @@ -55,7 +63,9 @@ const CannedResponseEdit = ({ cannedResponseData }: CannedResponseEditProps) => message: t(cannedResponseData?._id ? 'Canned_Response_Updated' : 'Canned_Response_Created'), }); router.navigate('/omnichannel/canned-responses'); - queryClient.invalidateQueries(['getCannedResponses']); + queryClient.invalidateQueries({ + queryKey: ['getCannedResponses'], + }); } catch (error) { dispatchToastMessage({ type: 'error', message: error }); } diff --git a/apps/meteor/client/omnichannel/cannedResponses/CannedResponseEditWithData.tsx b/apps/meteor/client/omnichannel/cannedResponses/CannedResponseEditWithData.tsx index cf4ab9523cb4..e6e457241e82 100644 --- a/apps/meteor/client/omnichannel/cannedResponses/CannedResponseEditWithData.tsx +++ b/apps/meteor/client/omnichannel/cannedResponses/CannedResponseEditWithData.tsx @@ -12,9 +12,12 @@ const CannedResponseEditWithData = ({ cannedResponseId }: { cannedResponseId: IO const { t } = useTranslation(); const getCannedResponseById = useEndpoint('GET', '/v1/canned-responses/:_id', { _id: cannedResponseId }); - const { data, isLoading, isError } = useQuery(['getCannedResponseById', cannedResponseId], async () => getCannedResponseById()); + const { data, isPending, isError } = useQuery({ + queryKey: ['getCannedResponseById', cannedResponseId], + queryFn: async () => getCannedResponseById(), + }); - if (isLoading) { + if (isPending) { return ; } @@ -30,7 +33,7 @@ const CannedResponseEditWithData = ({ cannedResponseId }: { cannedResponseId: IO return ; } - return ; + return ; }; export default CannedResponseEditWithData; diff --git a/apps/meteor/client/omnichannel/cannedResponses/CannedResponsesTable.tsx b/apps/meteor/client/omnichannel/cannedResponses/CannedResponsesTable.tsx index 50b720664c1b..eed4eb0978fc 100644 --- a/apps/meteor/client/omnichannel/cannedResponses/CannedResponsesTable.tsx +++ b/apps/meteor/client/omnichannel/cannedResponses/CannedResponsesTable.tsx @@ -1,8 +1,8 @@ import { Box, IconButton, Pagination } from '@rocket.chat/fuselage'; -import { useDebouncedValue, useMutableCallback } from '@rocket.chat/fuselage-hooks'; +import { useDebouncedValue, useEffectEvent } from '@rocket.chat/fuselage-hooks'; import { UserAvatar } from '@rocket.chat/ui-avatar'; import { useTranslation, usePermission, useToastMessageDispatch, useEndpoint, useRouter } from '@rocket.chat/ui-contexts'; -import { useQuery, hashQueryKey } from '@tanstack/react-query'; +import { hashKey, useQuery } from '@tanstack/react-query'; import { useMemo, useState } from 'react'; import CannedResponseFilter from './CannedResponseFilter'; @@ -52,17 +52,19 @@ const CannedResponsesTable = () => { [createdBy, current, debouncedText, itemsPerPage, sharing, sortBy, sortDirection], ); - const [defaultQuery] = useState(hashQueryKey([query])); - const queryHasChanged = defaultQuery !== hashQueryKey([query]); + const [defaultQuery] = useState(hashKey([query])); + const queryHasChanged = defaultQuery !== hashKey([query]); const getCannedResponses = useEndpoint('GET', '/v1/canned-responses'); - const { data, isLoading, isSuccess } = useQuery(['getCannedResponses', query], () => getCannedResponses(query), { + const { data, isLoading, isSuccess } = useQuery({ + queryKey: ['getCannedResponses', query], + queryFn: () => getCannedResponses(query), refetchOnWindowFocus: false, }); - const handleAddNew = useMutableCallback(() => router.navigate('/omnichannel/canned-responses/new')); + const handleAddNew = useEffectEvent(() => router.navigate('/omnichannel/canned-responses/new')); - const onRowClick = useMutableCallback((id, scope) => (): void => { + const onRowClick = useEffectEvent((id, scope) => (): void => { if (scope === 'global' && isMonitor && !isManager) { return dispatchToastMessage({ type: 'error', diff --git a/apps/meteor/client/omnichannel/cannedResponses/contextualBar/CannedResponse/WrapCannedResponseList.tsx b/apps/meteor/client/omnichannel/cannedResponses/contextualBar/CannedResponse/WrapCannedResponseList.tsx index 85c3e580c7a6..6ba47ef6142c 100644 --- a/apps/meteor/client/omnichannel/cannedResponses/contextualBar/CannedResponse/WrapCannedResponseList.tsx +++ b/apps/meteor/client/omnichannel/cannedResponses/contextualBar/CannedResponse/WrapCannedResponseList.tsx @@ -1,4 +1,4 @@ -import { useDebouncedValue, useLocalStorage, useMutableCallback } from '@rocket.chat/fuselage-hooks'; +import { useDebouncedValue, useLocalStorage, useEffectEvent } from '@rocket.chat/fuselage-hooks'; import { useSetModal, useRouter } from '@rocket.chat/ui-contexts'; import type { ChangeEvent, MouseEvent } from 'react'; import { memo, useCallback, useMemo, useState } from 'react'; @@ -38,7 +38,7 @@ export const WrapCannedResponseList = () => { ); const { phase, items, itemCount } = useRecordList(cannedList); - const onClickItem = useMutableCallback((data) => { + const onClickItem = useEffectEvent((data) => { const { _id: context } = data; router.navigate({ diff --git a/apps/meteor/client/omnichannel/cannedResponses/modals/CreateCannedResponse/CreateCannedResponseModal.tsx b/apps/meteor/client/omnichannel/cannedResponses/modals/CreateCannedResponse/CreateCannedResponseModal.tsx index 33c54616e1e5..59fcfb4547b8 100644 --- a/apps/meteor/client/omnichannel/cannedResponses/modals/CreateCannedResponse/CreateCannedResponseModal.tsx +++ b/apps/meteor/client/omnichannel/cannedResponses/modals/CreateCannedResponse/CreateCannedResponseModal.tsx @@ -8,6 +8,18 @@ import { useTranslation } from 'react-i18next'; import GenericModal from '../../../../components/GenericModal'; import CannedResponseForm from '../../components/cannedResponseForm'; +type CreateCannedResponseModalFormData = { + _id: string; + shortcut: string; + text: string; + tags: { + label: string; + value: string; + }[]; + scope: string; + departmentId: string; +}; + const getInitialData = ( cannedResponseData: (IOmnichannelCannedResponse & { departmentName: ILivechatDepartment['name'] }) | undefined, ) => ({ @@ -22,19 +34,17 @@ const getInitialData = ( departmentId: cannedResponseData?.departmentId || '', }); -const CreateCannedResponseModal = ({ - cannedResponseData, - onClose, - reloadCannedList, -}: { +type CreateCannedResponseModalProps = { cannedResponseData?: IOmnichannelCannedResponse & { departmentName: ILivechatDepartment['name'] }; onClose: () => void; reloadCannedList: () => void; -}) => { +}; + +const CreateCannedResponseModal = ({ cannedResponseData, onClose, reloadCannedList }: CreateCannedResponseModalProps) => { const { t } = useTranslation(); const dispatchToastMessage = useToastMessageDispatch(); - const methods = useForm({ defaultValues: getInitialData(cannedResponseData) }); + const methods = useForm({ defaultValues: getInitialData(cannedResponseData) }); const { handleSubmit, formState: { isDirty }, @@ -43,10 +53,9 @@ const CreateCannedResponseModal = ({ const saveCannedResponse = useEndpoint('POST', '/v1/canned-responses'); const handleCreate = useCallback( - async ({ departmentId, ...data }) => { + async ({ departmentId, ...data }: CreateCannedResponseModalFormData) => { try { await saveCannedResponse({ - _id: cannedResponseData?._id, ...data, ...(departmentId && { departmentId }), }); diff --git a/apps/meteor/client/omnichannel/cannedResponses/useRemoveCannedResponse.tsx b/apps/meteor/client/omnichannel/cannedResponses/useRemoveCannedResponse.tsx index 850767336283..f6bcc964c609 100644 --- a/apps/meteor/client/omnichannel/cannedResponses/useRemoveCannedResponse.tsx +++ b/apps/meteor/client/omnichannel/cannedResponses/useRemoveCannedResponse.tsx @@ -1,4 +1,4 @@ -import { useMutableCallback } from '@rocket.chat/fuselage-hooks'; +import { useEffectEvent } from '@rocket.chat/fuselage-hooks'; import { useSetModal, useToastMessageDispatch, useRouter, useMethod } from '@rocket.chat/ui-contexts'; import { useQueryClient } from '@tanstack/react-query'; import { useTranslation } from 'react-i18next'; @@ -14,11 +14,13 @@ export const useRemoveCannedResponse = () => { const dispatchToastMessage = useToastMessageDispatch(); const removeCannedResponse = useMethod('removeCannedResponse'); - const handleDelete = useMutableCallback((id) => { + const handleDelete = useEffectEvent((id) => { const onDeleteCannedResponse: () => Promise = async () => { try { await removeCannedResponse(id); - queryClient.invalidateQueries(['getCannedResponses']); + queryClient.invalidateQueries({ + queryKey: ['getCannedResponses'], + }); router.navigate('/omnichannel/canned-responses'); dispatchToastMessage({ type: 'success', message: t('Canned_Response_Removed') }); } catch (error) { diff --git a/apps/meteor/client/omnichannel/hooks/useCannedResponseList.ts b/apps/meteor/client/omnichannel/hooks/useCannedResponseList.ts index 6e02f302e3e1..f3901f921cf8 100644 --- a/apps/meteor/client/omnichannel/hooks/useCannedResponseList.ts +++ b/apps/meteor/client/omnichannel/hooks/useCannedResponseList.ts @@ -30,7 +30,7 @@ export const useCannedResponseList = ( const getDepartments = useEndpoint('GET', '/v1/livechat/department'); const fetchData = useCallback( - async (start, end) => { + async (start: number, end: number) => { const { cannedResponses, total } = await getCannedResponses({ ...(options.filter && { text: options.filter }), ...(options.type && ['global', 'user'].find((option) => option === options.type) && { scope: options.type }), diff --git a/apps/meteor/client/omnichannel/hooks/useOmnichannelPrioritiesMenu.tsx b/apps/meteor/client/omnichannel/hooks/useOmnichannelPrioritiesMenu.tsx index 1f6b01f2f110..9fbdc8be019c 100644 --- a/apps/meteor/client/omnichannel/hooks/useOmnichannelPrioritiesMenu.tsx +++ b/apps/meteor/client/omnichannel/hooks/useOmnichannelPrioritiesMenu.tsx @@ -1,6 +1,6 @@ import { LivechatPriorityWeight } from '@rocket.chat/core-typings'; import type { Menu } from '@rocket.chat/fuselage'; -import { useMutableCallback } from '@rocket.chat/fuselage-hooks'; +import { useEffectEvent } from '@rocket.chat/fuselage-hooks'; import { useEndpoint } from '@rocket.chat/ui-contexts'; import { useQueryClient } from '@tanstack/react-query'; import type { ComponentProps } from 'react'; @@ -18,11 +18,15 @@ export const useOmnichannelPrioritiesMenu = (rid: string): ComponentProps async () => { + const handlePriorityChange = useEffectEvent((priorityId: string) => async () => { try { priorityId ? await updateRoomPriority({ priorityId }) : await removeRoomPriority(); - queryClient.invalidateQueries(['current-chats']); - queryClient.invalidateQueries(['/v1/rooms.info', rid]); + queryClient.invalidateQueries({ + queryKey: ['current-chats'], + }); + queryClient.invalidateQueries({ + queryKey: ['/v1/rooms.info', rid], + }); } catch (error) { dispatchToastMessage({ type: 'error', message: error }); } diff --git a/apps/meteor/client/omnichannel/monitors/MonitorsTable.tsx b/apps/meteor/client/omnichannel/monitors/MonitorsTable.tsx index ac36e7a81301..be14aaff923e 100644 --- a/apps/meteor/client/omnichannel/monitors/MonitorsTable.tsx +++ b/apps/meteor/client/omnichannel/monitors/MonitorsTable.tsx @@ -15,7 +15,7 @@ import { import { useDebouncedValue } from '@rocket.chat/fuselage-hooks'; import { UserAutoComplete } from '@rocket.chat/ui-client'; import { useTranslation, useToastMessageDispatch, useMethod, useEndpoint, useSetModal } from '@rocket.chat/ui-contexts'; -import { useMutation, useQuery, hashQueryKey } from '@tanstack/react-query'; +import { useMutation, useQuery, hashKey, useQueryClient } from '@tanstack/react-query'; import { useMemo, useState } from 'react'; import FilterByText from '../../components/FilterByText'; @@ -32,7 +32,6 @@ import { } from '../../components/GenericTable'; import { usePagination } from '../../components/GenericTable/hooks/usePagination'; import { useSort } from '../../components/GenericTable/hooks/useSort'; -import { queryClient } from '../../lib/queryClient'; const MonitorsTable = () => { const t = useTranslation(); @@ -68,16 +67,21 @@ const MonitorsTable = () => { 500, ); - const { data, refetch, isLoading, isSuccess, isError } = useQuery(['omnichannel', 'monitors', query], () => getMonitors(query)); + const { data, refetch, isLoading, isSuccess, isError } = useQuery({ + queryKey: ['omnichannel', 'monitors', query], + queryFn: () => getMonitors(query), + }); + + const [defaultQuery] = useState(hashKey([query])); + const queryHasChanged = defaultQuery !== hashKey([query]); - const [defaultQuery] = useState(hashQueryKey([query])); - const queryHasChanged = defaultQuery !== hashQueryKey([query]); + const queryClient = useQueryClient(); const addMutation = useMutation({ mutationFn: async (username: string) => { await addMonitor(username); - await queryClient.invalidateQueries(['omnichannel', 'monitors']); + await queryClient.invalidateQueries({ queryKey: ['omnichannel', 'monitors'] }); }, onSuccess: () => { setUsername(''); @@ -100,7 +104,7 @@ const MonitorsTable = () => { } catch (error) { dispatchToastMessage({ type: 'error', message: error }); } - queryClient.invalidateQueries(['omnichannel', 'monitors']); + queryClient.invalidateQueries({ queryKey: ['omnichannel', 'monitors'] }); setModal(); }; @@ -138,7 +142,7 @@ const MonitorsTable = () => { {t('Username')} void} /> - diff --git a/apps/meteor/client/omnichannel/priorities/PrioritiesPage.tsx b/apps/meteor/client/omnichannel/priorities/PrioritiesPage.tsx index 9c98100259f6..8d398b1da6af 100644 --- a/apps/meteor/client/omnichannel/priorities/PrioritiesPage.tsx +++ b/apps/meteor/client/omnichannel/priorities/PrioritiesPage.tsx @@ -1,5 +1,5 @@ import { Button, ButtonGroup } from '@rocket.chat/fuselage'; -import { useMutableCallback } from '@rocket.chat/fuselage-hooks'; +import { useEffectEvent } from '@rocket.chat/fuselage-hooks'; import { useEndpoint, useRoute, useSetModal, useToastMessageDispatch } from '@rocket.chat/ui-contexts'; import { useQueryClient } from '@tanstack/react-query'; import type { ReactElement } from 'react'; @@ -42,7 +42,10 @@ export const PrioritiesPage = ({ priorityId, context }: PrioritiesPageProps): Re setModal(null); await resetPriorities(); - await queryClient.invalidateQueries(['/v1/livechat/priorities'], { exact: true }); + await queryClient.invalidateQueries({ + queryKey: ['/v1/livechat/priorities'], + exact: true, + }); prioritiesRoute.push({}); dispatchToastMessage({ type: 'success', message: t('Priorities_restored') }); @@ -56,7 +59,7 @@ export const PrioritiesPage = ({ priorityId, context }: PrioritiesPageProps): Re setModal( setModal(null)} />); }; - const onRowClick = useMutableCallback((id: string): void => { + const onRowClick = useEffectEvent((id: string): void => { prioritiesRoute.push({ context: 'edit', id }); }); @@ -66,10 +69,15 @@ export const PrioritiesPage = ({ priorityId, context }: PrioritiesPageProps): Re const onSavePriority = async ({ reset, ...payload }: PriorityFormData): Promise => { await savePriority(reset ? { reset } : payload); - await queryClient.invalidateQueries(['/v1/livechat/priorities']); + await queryClient.invalidateQueries({ + queryKey: ['/v1/livechat/priorities'], + }); dispatchToastMessage({ type: 'success', message: t('Priority_saved') }); - await queryClient.invalidateQueries(['/v1/livechat/priorities'], { exact: true }); + await queryClient.invalidateQueries({ + queryKey: ['/v1/livechat/priorities'], + exact: true, + }); prioritiesRoute.push({}); }; diff --git a/apps/meteor/client/omnichannel/priorities/PriorityEditForm.tsx b/apps/meteor/client/omnichannel/priorities/PriorityEditForm.tsx index 8492680f68d0..288cc5ae6351 100644 --- a/apps/meteor/client/omnichannel/priorities/PriorityEditForm.tsx +++ b/apps/meteor/client/omnichannel/priorities/PriorityEditForm.tsx @@ -1,6 +1,6 @@ import type { ILivechatPriority, Serialized } from '@rocket.chat/core-typings'; import { Field, FieldError, Button, Box, ButtonGroup } from '@rocket.chat/fuselage'; -import { useMutableCallback } from '@rocket.chat/fuselage-hooks'; +import { useEffectEvent } from '@rocket.chat/fuselage-hooks'; import type { TranslationKey } from '@rocket.chat/ui-contexts'; import { useToastMessageDispatch } from '@rocket.chat/ui-contexts'; import type { ReactElement } from 'react'; @@ -44,7 +44,7 @@ const PriorityEditForm = ({ data, onSave, onCancel }: PriorityEditFormProps): Re defaultValues: data ? { name: dirty ? name : defaultName } : {}, }); - const handleSave = useMutableCallback(async () => { + const handleSave = useEffectEvent(async () => { const { name } = getValues(); if (!isValid) { diff --git a/apps/meteor/client/omnichannel/priorities/PriorityEditFormWithData.tsx b/apps/meteor/client/omnichannel/priorities/PriorityEditFormWithData.tsx index 6a26a5a83449..8ab891423182 100644 --- a/apps/meteor/client/omnichannel/priorities/PriorityEditFormWithData.tsx +++ b/apps/meteor/client/omnichannel/priorities/PriorityEditFormWithData.tsx @@ -13,9 +13,9 @@ type PriorityEditFormWithDataProps = Omit & { function PriorityEditFormWithData({ priorityId, ...props }: PriorityEditFormWithDataProps): ReactElement { const { t } = useTranslation(); - const { data, isInitialLoading, isError } = usePriorityInfo(priorityId); + const { data, isLoading, isError } = usePriorityInfo(priorityId); - if (isInitialLoading) { + if (isLoading) { return ; } diff --git a/apps/meteor/client/omnichannel/reports/components/AgentsTable.tsx b/apps/meteor/client/omnichannel/reports/components/AgentsTable.tsx index 044d09792a4d..e1effedb296d 100644 --- a/apps/meteor/client/omnichannel/reports/components/AgentsTable.tsx +++ b/apps/meteor/client/omnichannel/reports/components/AgentsTable.tsx @@ -1,4 +1,4 @@ -import { useMutableCallback } from '@rocket.chat/fuselage-hooks'; +import { useEffectEvent } from '@rocket.chat/fuselage-hooks'; import { memo } from 'react'; import { useTranslation } from 'react-i18next'; @@ -24,7 +24,7 @@ type AgentsTableProps = { export const AgentsTable = memo(({ data, sortBy, sortDirection, setSort }: AgentsTableProps) => { const { t } = useTranslation(); - const onHeaderClick = useMutableCallback((id) => { + const onHeaderClick = useEffectEvent((id) => { setSort(id, sortDirection === 'asc' ? 'desc' : 'asc'); }); diff --git a/apps/meteor/client/omnichannel/reports/components/ReportCard.tsx b/apps/meteor/client/omnichannel/reports/components/ReportCard.tsx index ee8abb02b7fb..f6d2f2eaaf26 100644 --- a/apps/meteor/client/omnichannel/reports/components/ReportCard.tsx +++ b/apps/meteor/client/omnichannel/reports/components/ReportCard.tsx @@ -12,7 +12,7 @@ type ReportCardProps = { children: ReactElement; periodSelectorProps: ComponentProps; downloadProps: ComponentProps; - isLoading?: boolean; + isPending?: boolean; isDataFound?: boolean; minHeight?: number; subtitle?: string; @@ -23,12 +23,12 @@ type ReportCardProps = { }; export const ReportCard = forwardRef(function ReportCard( - { id, title, children, periodSelectorProps, downloadProps, isLoading, isDataFound, subtitle, emptyStateSubtitle, isError, onRetry }, + { id, title, children, periodSelectorProps, downloadProps, isPending, isDataFound, subtitle, emptyStateSubtitle, isError, onRetry }, ref, ) { return ( - + {title} @@ -46,7 +46,7 @@ export const ReportCard = forwardRef(function Repo void; children: ReactElement; }; -export const ReportCardContent = ({ isLoading, isError, isDataFound, subtitle, onRetry, children }: ReportCardContentProps) => { - if (isLoading) { +export const ReportCardContent = ({ isPending, isError, isDataFound, subtitle, onRetry, children }: ReportCardContentProps) => { + if (isPending) { return ; } if (isError) { diff --git a/apps/meteor/client/omnichannel/reports/hooks/useAgentsSection.tsx b/apps/meteor/client/omnichannel/reports/hooks/useAgentsSection.tsx index bf0f5f8e80bf..934d7ca6ebf9 100644 --- a/apps/meteor/client/omnichannel/reports/hooks/useAgentsSection.tsx +++ b/apps/meteor/client/omnichannel/reports/hooks/useAgentsSection.tsx @@ -25,12 +25,13 @@ export const useAgentsSection = () => { const { data: { data, total = 0, unspecified = 0 } = { data: [], total: 0 }, refetch, - isLoading, + isPending, isError, isSuccess, - } = useQuery( - ['omnichannel-reports', 'conversations-by-agent', period, sortBy, sortDirection], - async () => { + } = useQuery({ + queryKey: ['omnichannel-reports', 'conversations-by-agent', period, sortBy, sortDirection], + + queryFn: async () => { const { start, end } = getPeriodRange(period); const response = await getConversationsByAgent({ start: start.toISOString(), @@ -39,10 +40,9 @@ export const useAgentsSection = () => { }); return { ...response, data: formatChartData(response.data) }; }, - { - refetchInterval: 5 * 60 * 1000, - }, - ); + + refetchInterval: 5 * 60 * 1000, + }); const title = t('Conversations_by_agents'); @@ -65,7 +65,7 @@ export const useAgentsSection = () => { emptyStateSubtitle, data, total, - isLoading, + isPending, isError, isDataFound: isSuccess && data.length > 0, periodSelectorProps, @@ -82,7 +82,7 @@ export const useAgentsSection = () => { emptyStateSubtitle, data, total, - isLoading, + isPending, isError, isSuccess, periodSelectorProps, diff --git a/apps/meteor/client/omnichannel/reports/hooks/useChannelsSection.tsx b/apps/meteor/client/omnichannel/reports/hooks/useChannelsSection.tsx index 9a90fb982814..b7d4f47cc851 100644 --- a/apps/meteor/client/omnichannel/reports/hooks/useChannelsSection.tsx +++ b/apps/meteor/client/omnichannel/reports/hooks/useChannelsSection.tsx @@ -46,22 +46,22 @@ export const useChannelsSection = () => { const { data: { data, rawData, total } = { data: [], rawData: [], total: 0 }, refetch, - isLoading, + isPending, isError, isSuccess, - } = useQuery( - ['omnichannel-reports', 'conversations-by-source', period], - async () => { + } = useQuery({ + queryKey: ['omnichannel-reports', 'conversations-by-source', period], + + queryFn: async () => { const { start, end } = getPeriodRange(period); const response = await getConversationsBySource({ start: start.toISOString(), end: end.toISOString() }); const data = formatChartData(response.data, response.total, t); const displayData: DataItem[] = getTop(5, data, (value) => formatItem({ label: t('Others'), value }, response.total, t)); return { ...response, data: displayData, rawData: data }; }, - { - refetchInterval: 5 * 60 * 1000, - }, - ); + + refetchInterval: 5 * 60 * 1000, + }); const title = t('Conversations_by_channel'); const subtitle = t('__count__conversations__period__', { @@ -80,7 +80,7 @@ export const useChannelsSection = () => { emptyStateSubtitle, data, total, - isLoading, + isPending, isError, isDataFound: isSuccess && data.length > 0, periodSelectorProps, @@ -88,6 +88,6 @@ export const useChannelsSection = () => { downloadProps, onRetry: refetch, }), - [title, subtitle, emptyStateSubtitle, data, total, isLoading, isError, isSuccess, periodSelectorProps, period, downloadProps, refetch], + [title, subtitle, emptyStateSubtitle, data, total, isPending, isError, isSuccess, periodSelectorProps, period, downloadProps, refetch], ); }; diff --git a/apps/meteor/client/omnichannel/reports/hooks/useDepartmentsSection.tsx b/apps/meteor/client/omnichannel/reports/hooks/useDepartmentsSection.tsx index 57f30d0d38de..7ea2800c2c5e 100644 --- a/apps/meteor/client/omnichannel/reports/hooks/useDepartmentsSection.tsx +++ b/apps/meteor/client/omnichannel/reports/hooks/useDepartmentsSection.tsx @@ -22,21 +22,21 @@ export const useDepartmentsSection = () => { const { data: { data, total = 0, unspecified = 0 } = { data: [], total: 0 }, - isLoading, + isPending, isError, isSuccess, refetch, - } = useQuery( - ['omnichannel-reports', 'conversations-by-department', period], - async () => { + } = useQuery({ + queryKey: ['omnichannel-reports', 'conversations-by-department', period], + + queryFn: async () => { const { start, end } = getPeriodRange(period); const response = await getConversationsByDepartment({ start: start.toISOString(), end: end.toISOString() }); return { ...response, data: formatChartData(response.data) }; }, - { - refetchInterval: 5 * 60 * 1000, - }, - ); + + refetchInterval: 5 * 60 * 1000, + }); const title = t('Conversations_by_department'); const subtitleTotals = t('__departments__departments_and__count__conversations__period__', { @@ -58,7 +58,7 @@ export const useDepartmentsSection = () => { emptyStateSubtitle, data, total, - isLoading, + isPending, isError, isDataFound: isSuccess && data.length > 0, periodSelectorProps, @@ -66,6 +66,6 @@ export const useDepartmentsSection = () => { downloadProps, onRetry: refetch, }), - [title, subtitle, emptyStateSubtitle, data, total, isLoading, isError, isSuccess, periodSelectorProps, period, downloadProps, refetch], + [title, subtitle, emptyStateSubtitle, data, total, isPending, isError, isSuccess, periodSelectorProps, period, downloadProps, refetch], ); }; diff --git a/apps/meteor/client/omnichannel/reports/hooks/useStatusSection.tsx b/apps/meteor/client/omnichannel/reports/hooks/useStatusSection.tsx index d001a8bbeb5f..1ece5f941523 100644 --- a/apps/meteor/client/omnichannel/reports/hooks/useStatusSection.tsx +++ b/apps/meteor/client/omnichannel/reports/hooks/useStatusSection.tsx @@ -42,21 +42,21 @@ export const useStatusSection = () => { const { data: { data, total } = { data: [], total: 0 }, - isLoading, + isPending, isError, isSuccess, refetch, - } = useQuery( - ['omnichannel-reports', 'conversations-by-status', period, t], - async () => { + } = useQuery({ + queryKey: ['omnichannel-reports', 'conversations-by-status', period, t], + + queryFn: async () => { const response = await getConversationsByStatus({ start: start.toISOString(), end: end.toISOString() }); return { ...response, data: formatChartData(response.data, response.total, t) }; }, - { - refetchInterval: 5 * 60 * 1000, - }, - ); + + refetchInterval: 5 * 60 * 1000, + }); const title = t('Conversations_by_status'); const subtitle = t('__count__conversations__period__', { @@ -78,11 +78,11 @@ export const useStatusSection = () => { period, periodSelectorProps, downloadProps, - isLoading, + isPending, isError, isDataFound: isSuccess && data.length > 0, onRetry: refetch, }), - [title, subtitle, emptyStateSubtitle, data, total, period, periodSelectorProps, downloadProps, isLoading, isError, isSuccess, refetch], + [title, subtitle, emptyStateSubtitle, data, total, period, periodSelectorProps, downloadProps, isPending, isError, isSuccess, refetch], ); }; diff --git a/apps/meteor/client/omnichannel/reports/hooks/useTagsSection.tsx b/apps/meteor/client/omnichannel/reports/hooks/useTagsSection.tsx index 5ba58a71c879..37e9793c1c19 100644 --- a/apps/meteor/client/omnichannel/reports/hooks/useTagsSection.tsx +++ b/apps/meteor/client/omnichannel/reports/hooks/useTagsSection.tsx @@ -31,20 +31,20 @@ export const useTagsSection = () => { const { data: { data, total = 0, unspecified = 0 } = { data: [], total: 0 }, refetch, - isLoading, + isPending, isError, isSuccess, - } = useQuery( - ['omnichannel-reports', 'conversations-by-tags', period], - async () => { + } = useQuery({ + queryKey: ['omnichannel-reports', 'conversations-by-tags', period], + + queryFn: async () => { const { start, end } = getPeriodRange(period); const response = await getConversationsByTags({ start: start.toISOString(), end: end.toISOString() }); return { ...response, data: formatChartData(response.data) }; }, - { - refetchInterval: 5 * 60 * 1000, - }, - ); + + refetchInterval: 5 * 60 * 1000, + }); const title = t('Conversations_by_tag'); const subtitleTotals = t('__count__tags__and__count__conversations__period__', { @@ -70,10 +70,10 @@ export const useTagsSection = () => { periodSelectorProps, downloadProps, isError, - isLoading, + isPending, isDataFound: isSuccess && data.length > 0, onRetry: refetch, }), - [title, subtitle, emptyStateSubtitle, data, total, isError, isLoading, isSuccess, periodSelectorProps, period, downloadProps, refetch], + [title, subtitle, emptyStateSubtitle, data, total, isError, isPending, isSuccess, periodSelectorProps, period, downloadProps, refetch], ); }; diff --git a/apps/meteor/client/omnichannel/slaPolicies/RemoveSlaButton.tsx b/apps/meteor/client/omnichannel/slaPolicies/RemoveSlaButton.tsx index 36148d7e7356..510f99e8710c 100644 --- a/apps/meteor/client/omnichannel/slaPolicies/RemoveSlaButton.tsx +++ b/apps/meteor/client/omnichannel/slaPolicies/RemoveSlaButton.tsx @@ -1,5 +1,5 @@ import { IconButton } from '@rocket.chat/fuselage'; -import { useMutableCallback } from '@rocket.chat/fuselage-hooks'; +import { useEffectEvent } from '@rocket.chat/fuselage-hooks'; import { useRoute, useEndpoint, useSetModal, useToastMessageDispatch } from '@rocket.chat/ui-contexts'; import { useTranslation } from 'react-i18next'; @@ -14,7 +14,7 @@ const RemoveSlaButton = ({ _id, reload }: { _id: string; reload: () => void }) = const removeSLA = useEndpoint('DELETE', `/v1/livechat/sla/:slaId`, { slaId: _id }); - const handleDelete = useMutableCallback((e) => { + const handleDelete = useEffectEvent((e) => { e.stopPropagation(); const onDeleteAgent = async (): Promise => { try { diff --git a/apps/meteor/client/omnichannel/slaPolicies/SlaEdit.tsx b/apps/meteor/client/omnichannel/slaPolicies/SlaEdit.tsx index 374713acf2ea..fe8e0cf5f501 100644 --- a/apps/meteor/client/omnichannel/slaPolicies/SlaEdit.tsx +++ b/apps/meteor/client/omnichannel/slaPolicies/SlaEdit.tsx @@ -1,6 +1,6 @@ import type { IOmnichannelServiceLevelAgreements, Serialized } from '@rocket.chat/core-typings'; import { Field, FieldLabel, FieldRow, FieldError, TextInput, Button, Margins, Box, NumberInput } from '@rocket.chat/fuselage'; -import { useMutableCallback } from '@rocket.chat/fuselage-hooks'; +import { useEffectEvent } from '@rocket.chat/fuselage-hooks'; import { useToastMessageDispatch, useRoute, useTranslation, useEndpoint } from '@rocket.chat/ui-contexts'; import type { ReactElement } from 'react'; import { useController, useForm } from 'react-hook-form'; @@ -51,7 +51,7 @@ function SlaEdit({ data, isNew, slaId, reload, ...props }: SlaEditProps): ReactE const { field: descField } = useController({ control, name: 'description' }); - const handleSave = useMutableCallback(async () => { + const handleSave = useEffectEvent(async () => { const { name, description, dueTimeInMinutes } = getValues(); if (!isValid || !name || dueTimeInMinutes === undefined) { diff --git a/apps/meteor/client/omnichannel/slaPolicies/SlaEditWithData.tsx b/apps/meteor/client/omnichannel/slaPolicies/SlaEditWithData.tsx index 67560bc6e8a9..0f722340e26a 100644 --- a/apps/meteor/client/omnichannel/slaPolicies/SlaEditWithData.tsx +++ b/apps/meteor/client/omnichannel/slaPolicies/SlaEditWithData.tsx @@ -14,10 +14,13 @@ type SlaEditProps = { function SlaEditWithData({ slaId, reload }: SlaEditProps): ReactElement { const getSLA = useEndpoint('GET', `/v1/livechat/sla/:slaId`, { slaId }); - const { data, isLoading, isError } = useQuery(['/v1/livechat/sla', slaId], () => getSLA()); + const { data, isPending, isError } = useQuery({ + queryKey: ['/v1/livechat/sla', slaId], + queryFn: () => getSLA(), + }); const { t } = useTranslation(); - if (isLoading) { + if (isPending) { return ; } diff --git a/apps/meteor/client/omnichannel/slaPolicies/SlaPage.tsx b/apps/meteor/client/omnichannel/slaPolicies/SlaPage.tsx index 97abaef3be45..b20d47876eac 100644 --- a/apps/meteor/client/omnichannel/slaPolicies/SlaPage.tsx +++ b/apps/meteor/client/omnichannel/slaPolicies/SlaPage.tsx @@ -1,5 +1,5 @@ import { Button, ButtonGroup } from '@rocket.chat/fuselage'; -import { useMutableCallback } from '@rocket.chat/fuselage-hooks'; +import { useEffectEvent } from '@rocket.chat/fuselage-hooks'; import { useRouteParameter, useRoute } from '@rocket.chat/ui-contexts'; import { useRef, useCallback } from 'react'; import { useTranslation } from 'react-i18next'; @@ -28,7 +28,7 @@ const SlaPage = () => { reload.current(); }, []); - const handleClick = useMutableCallback(() => + const handleClick = useEffectEvent(() => slaPoliciesRoute.push({ context: 'new', }), diff --git a/apps/meteor/client/omnichannel/slaPolicies/SlaTable.tsx b/apps/meteor/client/omnichannel/slaPolicies/SlaTable.tsx index 098e0f948f37..e73993d6dfa5 100644 --- a/apps/meteor/client/omnichannel/slaPolicies/SlaTable.tsx +++ b/apps/meteor/client/omnichannel/slaPolicies/SlaTable.tsx @@ -1,7 +1,7 @@ import { Pagination } from '@rocket.chat/fuselage'; -import { useDebouncedValue, useMutableCallback } from '@rocket.chat/fuselage-hooks'; +import { useDebouncedValue, useEffectEvent } from '@rocket.chat/fuselage-hooks'; import { useTranslation, useEndpoint, useRouter } from '@rocket.chat/ui-contexts'; -import { useQuery, hashQueryKey } from '@tanstack/react-query'; +import { useQuery, hashKey } from '@tanstack/react-query'; import type { MutableRefObject } from 'react'; import { useMemo, useState, useEffect } from 'react'; @@ -43,17 +43,20 @@ const SlaTable = ({ reload }: { reload: MutableRefObject<() => void> }) => { ); const getSlaData = useEndpoint('GET', '/v1/livechat/sla'); - const { data, isSuccess, isLoading, refetch } = useQuery(['/v1/livechat/sla', query], () => getSlaData(query)); + const { data, isSuccess, isLoading, refetch } = useQuery({ + queryKey: ['/v1/livechat/sla', query], + queryFn: () => getSlaData(query), + }); - const [defaultQuery] = useState(hashQueryKey([query])); - const queryHasChanged = defaultQuery !== hashQueryKey([query]); + const [defaultQuery] = useState(hashKey([query])); + const queryHasChanged = defaultQuery !== hashKey([query]); useEffect(() => { reload.current = refetch; }, [reload, refetch]); - const handleAddNew = useMutableCallback(() => router.navigate('/omnichannel/sla-policies/new')); - const onRowClick = useMutableCallback((id) => () => router.navigate(`/omnichannel/sla-policies/edit/${id}`)); + const handleAddNew = useEffectEvent(() => router.navigate('/omnichannel/sla-policies/new')); + const onRowClick = useEffectEvent((id) => () => router.navigate(`/omnichannel/sla-policies/edit/${id}`)); const headers = ( <> diff --git a/apps/meteor/client/omnichannel/tags/TagEdit.tsx b/apps/meteor/client/omnichannel/tags/TagEdit.tsx index 0e700f6903df..6ad842940e68 100644 --- a/apps/meteor/client/omnichannel/tags/TagEdit.tsx +++ b/apps/meteor/client/omnichannel/tags/TagEdit.tsx @@ -1,6 +1,6 @@ import type { ILivechatDepartment, ILivechatTag, Serialized } from '@rocket.chat/core-typings'; import { Field, FieldLabel, FieldRow, FieldError, TextInput, Button, ButtonGroup, FieldGroup, Box } from '@rocket.chat/fuselage'; -import { useMutableCallback, useUniqueId } from '@rocket.chat/fuselage-hooks'; +import { useEffectEvent, useUniqueId } from '@rocket.chat/fuselage-hooks'; import { useToastMessageDispatch, useRouter, useMethod } from '@rocket.chat/ui-contexts'; import { useQueryClient } from '@tanstack/react-query'; import { useForm, Controller } from 'react-hook-form'; @@ -52,13 +52,15 @@ const TagEdit = ({ tagData, currentDepartments }: TagEditProps) => { }, }); - const handleSave = useMutableCallback(async ({ name, description, departments }: TagEditPayload) => { + const handleSave = useEffectEvent(async ({ name, description, departments }: TagEditPayload) => { const departmentsId = departments?.map((dep) => dep.value) || ['']; try { await saveTag(_id as unknown as string, { name, description }, departmentsId); dispatchToastMessage({ type: 'success', message: t('Saved') }); - queryClient.invalidateQueries(['livechat-tags']); + queryClient.invalidateQueries({ + queryKey: ['livechat-tags'], + }); } catch (error) { dispatchToastMessage({ type: 'error', message: error }); } finally { diff --git a/apps/meteor/client/omnichannel/tags/TagEditWithData.tsx b/apps/meteor/client/omnichannel/tags/TagEditWithData.tsx index 3b4dd345bd0c..15785952bd56 100644 --- a/apps/meteor/client/omnichannel/tags/TagEditWithData.tsx +++ b/apps/meteor/client/omnichannel/tags/TagEditWithData.tsx @@ -12,9 +12,13 @@ const TagEditWithData = ({ tagId }: { tagId: ILivechatTag['_id'] }) => { const { t } = useTranslation(); const getTagById = useEndpoint('GET', '/v1/livechat/tags/:tagId', { tagId }); - const { data, isLoading, isError } = useQuery(['livechat-getTagById', tagId], async () => getTagById(), { refetchOnWindowFocus: false }); + const { data, isPending, isError } = useQuery({ + queryKey: ['livechat-getTagById', tagId], + queryFn: async () => getTagById(), + refetchOnWindowFocus: false, + }); - if (isLoading) { + if (isPending) { return ; } diff --git a/apps/meteor/client/omnichannel/tags/TagEditWithDepartmentData.tsx b/apps/meteor/client/omnichannel/tags/TagEditWithDepartmentData.tsx index bac6b7d03741..1ec8de7a83ba 100644 --- a/apps/meteor/client/omnichannel/tags/TagEditWithDepartmentData.tsx +++ b/apps/meteor/client/omnichannel/tags/TagEditWithDepartmentData.tsx @@ -10,13 +10,13 @@ const TagEditWithDepartmentData = ({ tagData }: { tagData: ILivechatTag }) => { const t = useTranslation(); const getDepartmentsById = useEndpoint('GET', '/v1/livechat/department.listByIds'); - const { data, isLoading, isError } = useQuery( - ['livechat-getDepartmentsById', tagData.departments], - async () => getDepartmentsById({ ids: tagData.departments }), - { refetchOnWindowFocus: false }, - ); + const { data, isPending, isError } = useQuery({ + queryKey: ['livechat-getDepartmentsById', tagData.departments], + queryFn: async () => getDepartmentsById({ ids: tagData.departments }), + refetchOnWindowFocus: false, + }); - if (isLoading) { + if (isPending) { return ; } diff --git a/apps/meteor/client/omnichannel/tags/TagsTable.tsx b/apps/meteor/client/omnichannel/tags/TagsTable.tsx index 28f020aebb96..40b31e8d3d97 100644 --- a/apps/meteor/client/omnichannel/tags/TagsTable.tsx +++ b/apps/meteor/client/omnichannel/tags/TagsTable.tsx @@ -1,7 +1,7 @@ import { IconButton, Pagination } from '@rocket.chat/fuselage'; -import { useDebouncedValue, useMutableCallback } from '@rocket.chat/fuselage-hooks'; +import { useDebouncedValue, useEffectEvent } from '@rocket.chat/fuselage-hooks'; import { useTranslation, useEndpoint, useRouter } from '@rocket.chat/ui-contexts'; -import { useQuery, hashQueryKey } from '@tanstack/react-query'; +import { useQuery, hashKey } from '@tanstack/react-query'; import { useMemo, useState } from 'react'; import { useRemoveTag } from './useRemoveTag'; @@ -27,8 +27,8 @@ const TagsTable = () => { const { current, itemsPerPage, setItemsPerPage: onSetItemsPerPage, setCurrent: onSetCurrent, ...paginationProps } = usePagination(); const { sortBy, sortDirection, setSort } = useSort<'name' | 'description'>('name'); - const onRowClick = useMutableCallback((id) => router.navigate(`/omnichannel/tags/edit/${id}`)); - const handleAddNew = useMutableCallback(() => router.navigate('/omnichannel/tags/new')); + const onRowClick = useEffectEvent((id) => router.navigate(`/omnichannel/tags/edit/${id}`)); + const handleAddNew = useEffectEvent(() => router.navigate('/omnichannel/tags/new')); const handleDeleteTag = useRemoveTag(); const query = useDebouncedValue( @@ -46,10 +46,14 @@ const TagsTable = () => { ); const getTags = useEndpoint('GET', '/v1/livechat/tags'); - const { data, isSuccess, isLoading } = useQuery(['livechat-tags', query], async () => getTags(query), { refetchOnWindowFocus: false }); + const { data, isSuccess, isLoading } = useQuery({ + queryKey: ['livechat-tags', query], + queryFn: async () => getTags(query), + refetchOnWindowFocus: false, + }); - const [defaultQuery] = useState(hashQueryKey([query])); - const queryHasChanged = defaultQuery !== hashQueryKey([query]); + const [defaultQuery] = useState(hashKey([query])); + const queryHasChanged = defaultQuery !== hashKey([query]); const headers = ( <> diff --git a/apps/meteor/client/omnichannel/tags/useRemoveTag.tsx b/apps/meteor/client/omnichannel/tags/useRemoveTag.tsx index aaa5c980f09b..db62ac7c2342 100644 --- a/apps/meteor/client/omnichannel/tags/useRemoveTag.tsx +++ b/apps/meteor/client/omnichannel/tags/useRemoveTag.tsx @@ -1,4 +1,4 @@ -import { useMutableCallback } from '@rocket.chat/fuselage-hooks'; +import { useEffectEvent } from '@rocket.chat/fuselage-hooks'; import { useSetModal, useToastMessageDispatch, useRouter, useMethod } from '@rocket.chat/ui-contexts'; import { useQueryClient } from '@tanstack/react-query'; import { useTranslation } from 'react-i18next'; @@ -13,13 +13,15 @@ export const useRemoveTag = () => { const queryClient = useQueryClient(); const router = useRouter(); - const handleDeleteTag = useMutableCallback((tagId) => { + const handleDeleteTag = useEffectEvent((tagId) => { const handleDelete = async () => { try { await removeTag(tagId); dispatchToastMessage({ type: 'success', message: t('Tag_removed') }); router.navigate('/omnichannel/tags'); - queryClient.invalidateQueries(['livechat-tags']); + queryClient.invalidateQueries({ + queryKey: ['livechat-tags'], + }); } catch (error) { dispatchToastMessage({ type: 'error', message: error }); } finally { diff --git a/apps/meteor/client/omnichannel/units/UnitEdit.tsx b/apps/meteor/client/omnichannel/units/UnitEdit.tsx index 1d00819edafc..d1bae33242fa 100644 --- a/apps/meteor/client/omnichannel/units/UnitEdit.tsx +++ b/apps/meteor/client/omnichannel/units/UnitEdit.tsx @@ -14,7 +14,7 @@ import { FieldRow, CheckOption, } from '@rocket.chat/fuselage'; -import { useMutableCallback, useDebouncedValue, useUniqueId } from '@rocket.chat/fuselage-hooks'; +import { useEffectEvent, useDebouncedValue, useUniqueId } from '@rocket.chat/fuselage-hooks'; import { useToastMessageDispatch, useMethod, useTranslation, useRouter } from '@rocket.chat/ui-contexts'; import { useQueryClient } from '@tanstack/react-query'; import { useMemo, useState } from 'react'; @@ -127,7 +127,7 @@ const UnitEdit = ({ unitData, unitMonitors, unitDepartments }: UnitEditProps) => return [...mappedMonitorsItems, ...pending]; }, [monitors, monitorsItems]); - const handleSave = useMutableCallback(async ({ name, visibility }) => { + const handleSave = useEffectEvent(async ({ name, visibility }) => { const departmentsData = departments.map((department) => ({ departmentId: department.value })); const monitorsData = monitors.map((monitor) => ({ @@ -138,7 +138,9 @@ const UnitEdit = ({ unitData, unitMonitors, unitDepartments }: UnitEditProps) => try { await saveUnit(_id as unknown as string, { name, visibility }, monitorsData, departmentsData); dispatchToastMessage({ type: 'success', message: t('Saved') }); - queryClient.invalidateQueries(['livechat-units']); + queryClient.invalidateQueries({ + queryKey: ['livechat-units'], + }); router.navigate('/omnichannel/units'); } catch (error) { dispatchToastMessage({ type: 'error', message: error }); diff --git a/apps/meteor/client/omnichannel/units/UnitEditWithData.tsx b/apps/meteor/client/omnichannel/units/UnitEditWithData.tsx index fed6c8eaf14b..46e1bf608c76 100644 --- a/apps/meteor/client/omnichannel/units/UnitEditWithData.tsx +++ b/apps/meteor/client/omnichannel/units/UnitEditWithData.tsx @@ -18,17 +18,27 @@ const UnitEditWithData = ({ unitId }: { unitId: IOmnichannelBusinessUnit['_id'] data: unitData, isError, isLoading, - } = useQuery(['livechat-getUnitById', unitId], async () => getUnitById(), { refetchOnWindowFocus: false }); + } = useQuery({ + queryKey: ['livechat-getUnitById', unitId], + queryFn: async () => getUnitById(), + refetchOnWindowFocus: false, + }); const { data: unitMonitors, isError: unitMonitorsError, isLoading: unitMonitorsLoading, - } = useQuery(['livechat-getMonitorsByUnitId', unitId], async () => getMonitorsByUnitId({ unitId }), { refetchOnWindowFocus: false }); + } = useQuery({ + queryKey: ['livechat-getMonitorsByUnitId', unitId], + queryFn: async () => getMonitorsByUnitId({ unitId }), + refetchOnWindowFocus: false, + }); const { data: unitDepartments, isError: unitDepartmentsError, isLoading: unitDepartmentsLoading, - } = useQuery(['livechat-getDepartmentsByUnitId', unitId], async () => getDepartmentsByUnitId({ unitId }), { + } = useQuery({ + queryKey: ['livechat-getDepartmentsByUnitId', unitId], + queryFn: async () => getDepartmentsByUnitId({ unitId }), refetchOnWindowFocus: false, }); @@ -44,7 +54,7 @@ const UnitEditWithData = ({ unitId }: { unitId: IOmnichannelBusinessUnit['_id'] ); } - return ; + return ; }; export default UnitEditWithData; diff --git a/apps/meteor/client/omnichannel/units/UnitsTable.tsx b/apps/meteor/client/omnichannel/units/UnitsTable.tsx index 85bdda9d28a6..d62855bc430e 100644 --- a/apps/meteor/client/omnichannel/units/UnitsTable.tsx +++ b/apps/meteor/client/omnichannel/units/UnitsTable.tsx @@ -1,7 +1,7 @@ import { Pagination, IconButton } from '@rocket.chat/fuselage'; -import { useDebouncedValue, useMutableCallback } from '@rocket.chat/fuselage-hooks'; +import { useDebouncedValue, useEffectEvent } from '@rocket.chat/fuselage-hooks'; import { useEndpoint, useRouter } from '@rocket.chat/ui-contexts'; -import { useQuery, hashQueryKey } from '@tanstack/react-query'; +import { useQuery, hashKey } from '@tanstack/react-query'; import { useMemo, useState } from 'react'; import { useTranslation } from 'react-i18next'; @@ -42,13 +42,16 @@ const UnitsTable = () => { ); const getUnits = useEndpoint('GET', '/v1/livechat/units'); - const { isSuccess, isLoading, data } = useQuery(['livechat-units', query], async () => getUnits(query)); + const { isSuccess, isLoading, data } = useQuery({ + queryKey: ['livechat-units', query], + queryFn: async () => getUnits(query), + }); - const [defaultQuery] = useState(hashQueryKey([query])); - const queryHasChanged = defaultQuery !== hashQueryKey([query]); + const [defaultQuery] = useState(hashKey([query])); + const queryHasChanged = defaultQuery !== hashKey([query]); - const handleAddNew = useMutableCallback(() => router.navigate('/omnichannel/units/new')); - const onRowClick = useMutableCallback((id) => () => router.navigate(`/omnichannel/units/edit/${id}`)); + const handleAddNew = useEffectEvent(() => router.navigate('/omnichannel/units/new')); + const onRowClick = useEffectEvent((id) => () => router.navigate(`/omnichannel/units/edit/${id}`)); const handleDelete = useRemoveUnit(); const headers = ( diff --git a/apps/meteor/client/omnichannel/units/useRemoveUnit.tsx b/apps/meteor/client/omnichannel/units/useRemoveUnit.tsx index faf09b76442c..c07dd84baf78 100644 --- a/apps/meteor/client/omnichannel/units/useRemoveUnit.tsx +++ b/apps/meteor/client/omnichannel/units/useRemoveUnit.tsx @@ -1,4 +1,4 @@ -import { useMutableCallback } from '@rocket.chat/fuselage-hooks'; +import { useEffectEvent } from '@rocket.chat/fuselage-hooks'; import { useSetModal, useToastMessageDispatch, useMethod, useTranslation, useRouter } from '@rocket.chat/ui-contexts'; import { useQueryClient } from '@tanstack/react-query'; @@ -13,13 +13,15 @@ export const useRemoveUnit = () => { const queryClient = useQueryClient(); const removeUnit = useMethod('livechat:removeUnit'); - const handleDelete = useMutableCallback((id) => { + const handleDelete = useEffectEvent((id) => { const onDeleteAgent = async () => { try { await removeUnit(id); dispatchToastMessage({ type: 'success', message: t('Unit_removed') }); router.navigate('/omnichannel/units'); - queryClient.invalidateQueries(['livechat-units']); + queryClient.invalidateQueries({ + queryKey: ['livechat-units'], + }); } catch (error) { dispatchToastMessage({ type: 'error', message: error }); } finally { diff --git a/apps/meteor/client/providers/AppsProvider/AppsProvider.tsx b/apps/meteor/client/providers/AppsProvider/AppsProvider.tsx index 4fda5157424b..7030b04407e3 100644 --- a/apps/meteor/client/providers/AppsProvider/AppsProvider.tsx +++ b/apps/meteor/client/providers/AppsProvider/AppsProvider.tsx @@ -1,6 +1,6 @@ import { useDebouncedCallback } from '@rocket.chat/fuselage-hooks'; import { usePermission, useStream } from '@rocket.chat/ui-contexts'; -import { useQuery, useQueryClient } from '@tanstack/react-query'; +import { keepPreviousData, useQuery, useQueryClient } from '@tanstack/react-query'; import type { ReactNode } from 'react'; import { useEffect } from 'react'; @@ -44,7 +44,7 @@ const AppsProvider = ({ children }: AppsProviderProps) => { const queryClient = useQueryClient(); - const { isLoading: isLicenseInformationLoading, data: { license, limits } = {} } = useLicense({ loadValues: true }); + const { isPending: isLicenseInformationLoading, data: { license, limits } = {} } = useLicense({ loadValues: true }); const isEnterprise = isLicenseInformationLoading ? undefined : !!license; const invalidateAppsCountQuery = useInvalidateAppsCountQueryCallback(); @@ -54,7 +54,9 @@ const AppsProvider = ({ children }: AppsProviderProps) => { const invalidate = useDebouncedCallback( () => { - queryClient.invalidateQueries(['marketplace', 'apps-instance']); + queryClient.invalidateQueries({ + queryKey: ['marketplace', 'apps-instance'], + }); invalidateAppsCountQuery(); }, 100, @@ -72,26 +74,25 @@ const AppsProvider = ({ children }: AppsProviderProps) => { }); }, [invalidate, invalidateLicenseQuery, isEnterprise, stream]); - const marketplace = useQuery( - ['marketplace', 'apps-marketplace', isAdminUser], - async () => { + const marketplace = useQuery({ + queryKey: ['marketplace', 'apps-marketplace', isAdminUser], + + queryFn: async () => { const result = await AppClientOrchestratorInstance.getAppsFromMarketplace(isAdminUser); - queryClient.invalidateQueries(['marketplace', 'apps-stored']); if (result.error && typeof result.error === 'string') { throw new Error(result.error); } return result.apps; }, - { - staleTime: Infinity, - keepPreviousData: true, - onSettled: () => queryClient.invalidateQueries(['marketplace', 'apps-stored']), - }, - ); - const instance = useQuery( - ['marketplace', 'apps-instance', isAdminUser], - async () => { + staleTime: Infinity, + placeholderData: keepPreviousData, + }); + + const instance = useQuery({ + queryKey: ['marketplace', 'apps-instance', isAdminUser], + + queryFn: async () => { const result = await AppClientOrchestratorInstance.getInstalledApps().then((result: App[]) => result.map((current: App) => ({ ...current, @@ -100,24 +101,28 @@ const AppsProvider = ({ children }: AppsProviderProps) => { ); return result; }, - { - staleTime: Infinity, - refetchOnMount: 'always', - onSettled: () => queryClient.invalidateQueries(['marketplace', 'apps-stored']), - }, - ); - const { isLoading: isMarketplaceDataLoading, data: marketplaceData } = useQuery( - ['marketplace', 'apps-stored', instance.data, marketplace.data], - () => storeQueryFunction(marketplace, instance), - { - enabled: marketplace.isFetched && instance.isFetched, - keepPreviousData: true, - }, - ); + staleTime: Infinity, + refetchOnMount: 'always', + }); + + const { isPending: isMarketplaceDataLoading, data: marketplaceData } = useQuery({ + queryKey: ['marketplace', 'apps-stored', instance.data, marketplace.data], + queryFn: () => storeQueryFunction(marketplace, instance), + enabled: marketplace.isFetched && instance.isFetched, + placeholderData: keepPreviousData, + }); const [marketplaceAppsData, installedAppsData, privateAppsData] = marketplaceData || []; + useEffect(() => { + if (instance.data && marketplace.data) { + queryClient.invalidateQueries({ + queryKey: ['marketplace', 'apps-stored'], + }); + } + }, [marketplace.data, instance.data, queryClient]); + return ( { privateApps: getAppState(isMarketplaceDataLoading, privateAppsData), reload: async () => { - await Promise.all([queryClient.invalidateQueries(['marketplace'])]); + await Promise.all([ + queryClient.invalidateQueries({ + queryKey: ['marketplace'], + }), + ]); }, orchestrator: AppClientOrchestratorInstance, privateAppsEnabled: (limits?.privateApps?.max ?? 0) !== 0, diff --git a/apps/meteor/client/providers/CallProvider/CallProvider.tsx b/apps/meteor/client/providers/CallProvider/CallProvider.tsx index 6110cf217fbb..fd86f6376ee8 100644 --- a/apps/meteor/client/providers/CallProvider/CallProvider.tsx +++ b/apps/meteor/client/providers/CallProvider/CallProvider.tsx @@ -9,7 +9,7 @@ import { isVoipEventCallAbandoned, UserState, } from '@rocket.chat/core-typings'; -import { useMutableCallback } from '@rocket.chat/fuselage-hooks'; +import { useEffectEvent } from '@rocket.chat/fuselage-hooks'; import { Random } from '@rocket.chat/random'; import type { Device } from '@rocket.chat/ui-contexts'; import { @@ -76,7 +76,12 @@ export const CallProvider = ({ children }: CallProviderProps) => { const voipSounds = useVoipSounds(); const closeRoom = useCallback( - async (data = {}): Promise => { + async ( + data: { + comment?: string; + tags?: string[]; + } = {}, + ): Promise => { roomInfo && (await voipCloseRoomEndpoint({ rid: roomInfo.rid, @@ -94,15 +99,15 @@ export const CallProvider = ({ children }: CallProviderProps) => { ); const openWrapUpModal = useCallback((): void => { - setModal(() => ); + setModal(); }, [closeRoom, setModal]); - const changeAudioOutputDevice = useMutableCallback((selectedAudioDevice: Device): void => { + const changeAudioOutputDevice = useEffectEvent((selectedAudioDevice: Device): void => { remoteAudioMediaRef?.current && setOutputMediaDevice({ outputDevice: selectedAudioDevice, HTMLAudioElement: remoteAudioMediaRef.current }); }); - const changeAudioInputDevice = useMutableCallback((selectedAudioDevice: Device): void => { + const changeAudioInputDevice = useEffectEvent((selectedAudioDevice: Device): void => { if (!result.voipClient) { return; } diff --git a/apps/meteor/client/providers/DeviceProvider/DeviceProvider.tsx b/apps/meteor/client/providers/DeviceProvider/DeviceProvider.tsx index 96f5ed367684..358f4e7ea998 100644 --- a/apps/meteor/client/providers/DeviceProvider/DeviceProvider.tsx +++ b/apps/meteor/client/providers/DeviceProvider/DeviceProvider.tsx @@ -1,4 +1,4 @@ -import { useMutableCallback } from '@rocket.chat/fuselage-hooks'; +import { useEffectEvent } from '@rocket.chat/fuselage-hooks'; import type { Device, DeviceContextValue } from '@rocket.chat/ui-contexts'; import { DeviceContext } from '@rocket.chat/ui-contexts'; import type { ReactElement, ReactNode } from 'react'; @@ -32,7 +32,7 @@ export const DeviceProvider = ({ children }: DeviceProviderProps): ReactElement setSelectedAudioInputDevice(device); }; - const setAudioOutputDevice = useMutableCallback( + const setAudioOutputDevice = useEffectEvent( ({ outputDevice, HTMLAudioElement }: { outputDevice: Device; HTMLAudioElement: HTMLAudioElement }): void => { if (!isSetSinkIdAvailable()) { throw new Error('setSinkId is not available in this browser'); diff --git a/apps/meteor/client/providers/OmnichannelProvider.tsx b/apps/meteor/client/providers/OmnichannelProvider.tsx index 487dfa475081..ed06c15d6873 100644 --- a/apps/meteor/client/providers/OmnichannelProvider.tsx +++ b/apps/meteor/client/providers/OmnichannelProvider.tsx @@ -78,9 +78,11 @@ const OmnichannelProvider = ({ children }: OmnichannelProviderProps) => { const { data: { priorities = [] } = {}, - isInitialLoading: isLoadingPriorities, + isLoading: isLoadingPriorities, isError: isErrorPriorities, - } = useQuery(['/v1/livechat/priorities'], () => getPriorities({ sort: JSON.stringify({ sortItem: 1 }) }), { + } = useQuery({ + queryKey: ['/v1/livechat/priorities'], + queryFn: () => getPriorities({ sort: JSON.stringify({ sortItem: 1 }) }), staleTime: Infinity, enabled: isPrioritiesEnabled, }); @@ -93,7 +95,9 @@ const OmnichannelProvider = ({ children }: OmnichannelProviderProps) => { } return subscribe('omnichannel.priority-changed', () => { - queryClient.invalidateQueries(['/v1/livechat/priorities']); + queryClient.invalidateQueries({ + queryKey: ['/v1/livechat/priorities'], + }); }); }, [isPrioritiesEnabled, queryClient, subscribe]); diff --git a/apps/meteor/client/providers/SettingsProvider.tsx b/apps/meteor/client/providers/SettingsProvider.tsx index 37959bcd78dc..b426b283c74a 100644 --- a/apps/meteor/client/providers/SettingsProvider.tsx +++ b/apps/meteor/client/providers/SettingsProvider.tsx @@ -1,12 +1,12 @@ import type { ISetting } from '@rocket.chat/core-typings'; import type { SettingsContextValue } from '@rocket.chat/ui-contexts'; import { SettingsContext, useAtLeastOnePermission, useMethod } from '@rocket.chat/ui-contexts'; +import { useQueryClient } from '@tanstack/react-query'; import { Tracker } from 'meteor/tracker'; import type { ReactNode } from 'react'; import { useCallback, useEffect, useMemo, useState } from 'react'; import { createReactiveSubscriptionFactory } from '../lib/createReactiveSubscriptionFactory'; -import { queryClient } from '../lib/queryClient'; import { PrivateSettingsCachedCollection } from '../lib/settings/PrivateSettingsCachedCollection'; import { PublicSettingsCachedCollection } from '../lib/settings/PublicSettingsCachedCollection'; @@ -89,26 +89,21 @@ const SettingsProvider = ({ children, privileged = false }: SettingsProviderProp [cachedCollection], ); - const settingsChangeCallback = (changes: { _id: string }[]): void => { - changes.forEach((val) => { - switch (val._id) { - case 'Enterprise_License': - queryClient.invalidateQueries(['licenses']); - break; - - default: - break; - } - }); - }; + const queryClient = useQueryClient(); const saveSettings = useMethod('saveSettings'); const dispatch = useCallback( - async (changes) => { - settingsChangeCallback(changes); - await saveSettings(changes); + async (changes: Partial[]) => { + // FIXME: This is a temporary solution to invalidate queries when settings change + changes.forEach((val) => { + if (val._id === 'Enterprise_License') { + queryClient.invalidateQueries({ queryKey: ['licenses'] }); + } + }); + + await saveSettings(changes as Pick[]); }, - [saveSettings], + [queryClient, saveSettings], ); const contextValue = useMemo( diff --git a/apps/meteor/client/providers/ToastMessagesProvider.tsx b/apps/meteor/client/providers/ToastMessagesProvider.tsx index c814106593d1..ba938f284e97 100644 --- a/apps/meteor/client/providers/ToastMessagesProvider.tsx +++ b/apps/meteor/client/providers/ToastMessagesProvider.tsx @@ -1,5 +1,7 @@ import { ToastBarProvider, useToastBarDispatch } from '@rocket.chat/fuselage-toastbar'; import { ToastMessagesContext } from '@rocket.chat/ui-contexts'; +import type { DefaultError, Query } from '@tanstack/react-query'; +import { useQueryClient } from '@tanstack/react-query'; import type { ReactNode } from 'react'; import { useEffect } from 'react'; @@ -17,6 +19,32 @@ type ToastMessageInnerProviderProps = { const ToastMessageInnerProvider = ({ children }: ToastMessageInnerProviderProps) => { const dispatchToastBar = useToastBarDispatch(); + const queryClient = useQueryClient(); + const queryCacheInstance = queryClient.getQueryCache(); + queryCacheInstance.config.onError = (error: DefaultError, query: Query) => { + const meta = query?.meta; + if (meta) { + const { errorToastMessage, apiErrorToastMessage } = meta as { + errorToastMessage?: string; + apiErrorToastMessage?: boolean; + }; + if (apiErrorToastMessage) { + dispatchToastMessage({ type: 'error', message: error }); + } else if (errorToastMessage) { + dispatchToastMessage({ type: 'error', message: errorToastMessage }); + } + } + }; + queryCacheInstance.config.onSuccess = (_, query: Query) => { + const meta = query?.meta; + if (meta) { + const { successToastMessage } = meta as { successToastMessage?: string }; + if (successToastMessage) { + dispatchToastMessage({ type: 'success', message: successToastMessage }); + } + } + }; + useEffect( () => subscribeToToastMessages(({ type, message, title = '' }) => { diff --git a/apps/meteor/client/providers/UserProvider/UserProvider.tsx b/apps/meteor/client/providers/UserProvider/UserProvider.tsx index 2e658e7e46b4..75f83f4edff0 100644 --- a/apps/meteor/client/providers/UserProvider/UserProvider.tsx +++ b/apps/meteor/client/providers/UserProvider/UserProvider.tsx @@ -2,6 +2,7 @@ import type { IRoom, ISubscription, IUser } from '@rocket.chat/core-typings'; import { useLocalStorage } from '@rocket.chat/fuselage-hooks'; import type { SubscriptionWithRoom } from '@rocket.chat/ui-contexts'; import { UserContext, useEndpoint } from '@rocket.chat/ui-contexts'; +import { useQueryClient } from '@tanstack/react-query'; import { Meteor } from 'meteor/meteor'; import type { ContextType, ReactElement, ReactNode } from 'react'; import { useEffect, useMemo, useRef } from 'react'; @@ -16,7 +17,6 @@ import { sdk } from '../../../app/utils/client/lib/SDKClient'; import { afterLogoutCleanUpCallback } from '../../../lib/callbacks/afterLogoutCleanUpCallback'; import { useReactiveValue } from '../../hooks/useReactiveValue'; import { createReactiveSubscriptionFactory } from '../../lib/createReactiveSubscriptionFactory'; -import { queryClient } from '../../lib/queryClient'; import { useCreateFontStyleElement } from '../../views/account/accessibility/hooks/useCreateFontStyleElement'; const getUser = (): IUser | null => Meteor.user() as IUser | null; @@ -94,13 +94,15 @@ const UserProvider = ({ children }: UserProviderProps): ReactElement => { } }, [preferedLanguage, setPreferedLanguage, setUserLanguage, user?.language, userLanguage, userId, setUserPreferences]); + const queryClient = useQueryClient(); + useEffect(() => { if (previousUserId.current && previousUserId.current !== userId) { queryClient.clear(); } previousUserId.current = userId; - }, [userId]); + }, [queryClient, userId]); return ; }; diff --git a/apps/meteor/client/sidebar/Item/Condensed.tsx b/apps/meteor/client/sidebar/Item/Condensed.tsx index b2f25ee67bec..792c39903393 100644 --- a/apps/meteor/client/sidebar/Item/Condensed.tsx +++ b/apps/meteor/client/sidebar/Item/Condensed.tsx @@ -1,5 +1,5 @@ import { IconButton, Sidebar } from '@rocket.chat/fuselage'; -import { useMutableCallback, usePrefersReducedMotion } from '@rocket.chat/fuselage-hooks'; +import { useEffectEvent, usePrefersReducedMotion } from '@rocket.chat/fuselage-hooks'; import type { Keys as IconName } from '@rocket.chat/icons'; import type { ReactElement } from 'react'; import { memo, useState } from 'react'; @@ -24,7 +24,7 @@ const Condensed = ({ icon, title = '', avatar, actions, href, unread, menu, badg const isReduceMotionEnabled = usePrefersReducedMotion(); - const handleMenu = useMutableCallback((e) => { + const handleMenu = useEffectEvent((e) => { setMenuVisibility(e.target.offsetWidth > 0 && Boolean(menu)); }); const handleMenuEvent = { diff --git a/apps/meteor/client/sidebar/Item/Extended.tsx b/apps/meteor/client/sidebar/Item/Extended.tsx index 3a1fa668eeb0..e236f8660bc7 100644 --- a/apps/meteor/client/sidebar/Item/Extended.tsx +++ b/apps/meteor/client/sidebar/Item/Extended.tsx @@ -1,5 +1,5 @@ import { Sidebar, IconButton } from '@rocket.chat/fuselage'; -import { useMutableCallback, usePrefersReducedMotion } from '@rocket.chat/fuselage-hooks'; +import { useEffectEvent, usePrefersReducedMotion } from '@rocket.chat/fuselage-hooks'; import type { Keys as IconName } from '@rocket.chat/icons'; import type { ReactNode } from 'react'; import { memo, useState } from 'react'; @@ -45,7 +45,7 @@ const Extended = ({ const isReduceMotionEnabled = usePrefersReducedMotion(); - const handleMenu = useMutableCallback((e) => { + const handleMenu = useEffectEvent((e) => { setMenuVisibility(e.target.offsetWidth > 0 && Boolean(menu)); }); diff --git a/apps/meteor/client/sidebar/Item/Medium.tsx b/apps/meteor/client/sidebar/Item/Medium.tsx index 44601ed94813..f1f37047ece4 100644 --- a/apps/meteor/client/sidebar/Item/Medium.tsx +++ b/apps/meteor/client/sidebar/Item/Medium.tsx @@ -1,5 +1,5 @@ import { Sidebar, IconButton } from '@rocket.chat/fuselage'; -import { useMutableCallback, usePrefersReducedMotion } from '@rocket.chat/fuselage-hooks'; +import { useEffectEvent, usePrefersReducedMotion } from '@rocket.chat/fuselage-hooks'; import type { ReactNode } from 'react'; import { memo, useState } from 'react'; @@ -22,7 +22,7 @@ const Medium = ({ icon, title = '', avatar, actions, href, badges, unread, menu, const isReduceMotionEnabled = usePrefersReducedMotion(); - const handleMenu = useMutableCallback((e) => { + const handleMenu = useEffectEvent((e) => { setMenuVisibility(e.target.offsetWidth > 0 && Boolean(menu)); }); const handleMenuEvent = { diff --git a/apps/meteor/client/sidebar/RoomMenu.tsx b/apps/meteor/client/sidebar/RoomMenu.tsx index 2e04f0cc9bec..14e453da5401 100644 --- a/apps/meteor/client/sidebar/RoomMenu.tsx +++ b/apps/meteor/client/sidebar/RoomMenu.tsx @@ -1,6 +1,6 @@ import type { RoomType } from '@rocket.chat/core-typings'; import { Option, Menu } from '@rocket.chat/fuselage'; -import { useMutableCallback } from '@rocket.chat/fuselage-hooks'; +import { useEffectEvent } from '@rocket.chat/fuselage-hooks'; import type { TranslationKey, Fields } from '@rocket.chat/ui-contexts'; import { useRouter, @@ -66,7 +66,7 @@ const RoomMenu = ({ const dispatchToastMessage = useToastMessageDispatch(); const setModal = useSetModal(); - const closeModal = useMutableCallback(() => setModal()); + const closeModal = useEffectEvent(() => setModal()); const router = useRouter(); @@ -102,7 +102,7 @@ const RoomMenu = ({ return !((cl != null && !cl) || ['d', 'l'].includes(type)); })(); - const handleLeave = useMutableCallback(() => { + const handleLeave = useEffectEvent(() => { const leave = async (): Promise => { try { await leaveRoom({ roomId: rid }); @@ -129,9 +129,11 @@ const RoomMenu = ({ ); }); - const handleToggleRead = useMutableCallback(async () => { + const handleToggleRead = useEffectEvent(async () => { try { - queryClient.invalidateQueries(['sidebar/search/spotlight']); + queryClient.invalidateQueries({ + queryKey: ['sidebar/search/spotlight'], + }); if (isUnread) { await readMessages({ rid, readThreads: true }); @@ -152,7 +154,7 @@ const RoomMenu = ({ } }); - const handleToggleFavorite = useMutableCallback(async () => { + const handleToggleFavorite = useEffectEvent(async () => { try { await toggleFavorite({ roomId: rid, favorite: !isFavorite }); } catch (error) { diff --git a/apps/meteor/client/sidebar/footer/SidebarFooterWatermark.tsx b/apps/meteor/client/sidebar/footer/SidebarFooterWatermark.tsx index 36a7657177c0..850f2160e1ad 100644 --- a/apps/meteor/client/sidebar/footer/SidebarFooterWatermark.tsx +++ b/apps/meteor/client/sidebar/footer/SidebarFooterWatermark.tsx @@ -21,7 +21,7 @@ export const SidebarFooterWatermark = (): ReactElement | null => { const license = response.data; - if (license.activeModules.includes('hide-watermark') && !license.trial) { + if (license?.activeModules.includes('hide-watermark') && !license.trial) { return null; } diff --git a/apps/meteor/client/sidebar/footer/voip/hooks/useOmnichannelContactLabel.ts b/apps/meteor/client/sidebar/footer/voip/hooks/useOmnichannelContactLabel.ts index 6b3d59830d1e..ded2b9021d78 100644 --- a/apps/meteor/client/sidebar/footer/voip/hooks/useOmnichannelContactLabel.ts +++ b/apps/meteor/client/sidebar/footer/voip/hooks/useOmnichannelContactLabel.ts @@ -8,7 +8,9 @@ export const useOmnichannelContactLabel = (caller: ICallerInfo): string => { const getContactBy = useEndpoint('GET', '/v1/omnichannel/contact.search'); const phone = parseOutboundPhoneNumber(caller.callerId); - const { data } = useQuery(['getContactsByPhone', phone], async () => getContactBy({ phone }).then(({ contact }) => contact), { + const { data } = useQuery({ + queryKey: ['getContactsByPhone', phone], + queryFn: async () => getContactBy({ phone }).then(({ contact }) => contact), enabled: !!phone, }); diff --git a/apps/meteor/client/sidebar/header/EditStatusModal.tsx b/apps/meteor/client/sidebar/header/EditStatusModal.tsx index bbc287c6ee59..6845ed052925 100644 --- a/apps/meteor/client/sidebar/header/EditStatusModal.tsx +++ b/apps/meteor/client/sidebar/header/EditStatusModal.tsx @@ -1,6 +1,6 @@ import type { IUser } from '@rocket.chat/core-typings'; import { Field, TextInput, FieldGroup, Modal, Button, Box, FieldLabel, FieldRow, FieldError, FieldHint } from '@rocket.chat/fuselage'; -import { useLocalStorage, useMutableCallback } from '@rocket.chat/fuselage-hooks'; +import { useLocalStorage, useEffectEvent } from '@rocket.chat/fuselage-hooks'; import { useToastMessageDispatch, useSetting, useTranslation, useEndpoint } from '@rocket.chat/ui-contexts'; import type { ReactElement, ChangeEvent, ComponentProps, FormEvent } from 'react'; import { useState, useCallback } from 'react'; @@ -27,7 +27,7 @@ const EditStatusModal = ({ onClose, userStatus, userStatusText }: EditStatusModa const setUserStatus = useEndpoint('POST', '/v1/users.setStatus'); - const handleStatusText = useMutableCallback((e: ChangeEvent): void => { + const handleStatusText = useEffectEvent((e: ChangeEvent): void => { setStatusText(e.currentTarget.value); if (statusText && statusText.length > USER_STATUS_TEXT_MAX_LENGTH) { diff --git a/apps/meteor/client/sidebar/header/MatrixFederationSearch/FederatedRoomList.tsx b/apps/meteor/client/sidebar/header/MatrixFederationSearch/FederatedRoomList.tsx index c7c5f01b2c3c..39f81e02b8e9 100644 --- a/apps/meteor/client/sidebar/header/MatrixFederationSearch/FederatedRoomList.tsx +++ b/apps/meteor/client/sidebar/header/MatrixFederationSearch/FederatedRoomList.tsx @@ -24,35 +24,36 @@ const FederatedRoomList = ({ serverName, roomName, count }: FederatedRoomListPro const setModal = useSetModal(); const { t } = useTranslation(); const dispatchToastMessage = useToastMessageDispatch(); - const { data, isLoading, isFetchingNextPage, fetchNextPage } = useInfiniteFederationSearchPublicRooms(serverName, roomName, count); + const { data, isPending, isFetchingNextPage, fetchNextPage } = useInfiniteFederationSearchPublicRooms(serverName, roomName, count); - const { mutate: onClickJoin, isLoading: isLoadingMutation } = useMutation( - ['federation/joinExternalPublicRoom'], - async ({ id, pageToken }: IFederationPublicRooms) => + const { mutate: onClickJoin, isPending: isLoadingMutation } = useMutation({ + mutationKey: ['federation/joinExternalPublicRoom'], + + mutationFn: async ({ id, pageToken }: IFederationPublicRooms) => joinExternalPublicRoom({ externalRoomId: id as `!${string}:${string}`, roomName, pageToken }), - { - onSuccess: (_, data) => { - dispatchToastMessage({ - type: 'success', - message: t('Your_request_to_join__roomName__has_been_made_it_could_take_up_to_15_minutes_to_be_processed', { - roomName: data.name, - }), - }); + + onSuccess: (_, data) => { + dispatchToastMessage({ + type: 'success', + message: t('Your_request_to_join__roomName__has_been_made_it_could_take_up_to_15_minutes_to_be_processed', { + roomName: data.name, + }), + }); + setModal(null); + }, + + onError: (error, { id }) => { + if (error instanceof Error && error.message === 'already-joined') { setModal(null); - }, - onError: (error, { id }) => { - if (error instanceof Error && error.message === 'already-joined') { - setModal(null); - roomCoordinator.openRouteLink('c', { rid: id }); - return; - } + roomCoordinator.openRouteLink('c', { rid: id }); + return; + } - dispatchToastMessage({ type: 'error', message: error }); - }, + dispatchToastMessage({ type: 'error', message: error }); }, - ); + }); - if (isLoading) { + if (isPending) { return ; } @@ -69,7 +70,7 @@ const FederatedRoomList = ({ serverName, roomName, count }: FederatedRoomListPro Scroller: VirtuosoScrollbars, EmptyPlaceholder: FederatedRoomListEmptyPlaceholder, }} - endReached={isLoading || isFetchingNextPage ? () => undefined : () => fetchNextPage()} + endReached={isPending || isFetchingNextPage ? () => undefined : () => fetchNextPage()} itemContent={(_, room) => ( onClickJoin(room)} {...room} disabled={isLoadingMutation} key={room.id} /> )} diff --git a/apps/meteor/client/sidebar/header/MatrixFederationSearch/MatrixFederationManageServerModal.tsx b/apps/meteor/client/sidebar/header/MatrixFederationSearch/MatrixFederationManageServerModal.tsx index b3fc846a98bd..d9b02d3c31b1 100644 --- a/apps/meteor/client/sidebar/header/MatrixFederationSearch/MatrixFederationManageServerModal.tsx +++ b/apps/meteor/client/sidebar/header/MatrixFederationSearch/MatrixFederationManageServerModal.tsx @@ -37,13 +37,19 @@ const MatrixFederationAddServerModal = ({ onClickClose }: MatrixFederationAddSer const { mutate: addServer, - isLoading, + isPending, isError, - } = useMutation(['v1/federation/addServerByUser', serverName], () => addMatrixServer({ serverName }), { + } = useMutation({ + mutationKey: ['v1/federation/addServerByUser', serverName], + mutationFn: () => addMatrixServer({ serverName }), + onSuccess: async () => { - await queryClient.invalidateQueries(['federation/listServersByUsers']); + await queryClient.invalidateQueries({ + queryKey: ['federation/listServersByUsers'], + }); setModal(); }, + onError: (error) => { const errorKey = getErrorKey(error); if (!errorKey) { @@ -54,7 +60,7 @@ const MatrixFederationAddServerModal = ({ onClickClose }: MatrixFederationAddSer }, }); - const { data, isLoading: isLoadingServerList } = useMatrixServerList(); + const { data, isPending: isLoadingServerList } = useMatrixServerList(); const titleId = useUniqueId(); const serverNameId = useUniqueId(); @@ -71,7 +77,7 @@ const MatrixFederationAddServerModal = ({ onClickClose }: MatrixFederationAddSer ) => { setServerName(e.currentTarget.value); @@ -81,7 +87,7 @@ const MatrixFederationAddServerModal = ({ onClickClose }: MatrixFederationAddSer }} mie={4} /> - diff --git a/apps/meteor/client/sidebar/header/MatrixFederationSearch/MatrixFederationRemoveServerList.tsx b/apps/meteor/client/sidebar/header/MatrixFederationSearch/MatrixFederationRemoveServerList.tsx index 51a05f3f3b5a..db05da903c8d 100644 --- a/apps/meteor/client/sidebar/header/MatrixFederationSearch/MatrixFederationRemoveServerList.tsx +++ b/apps/meteor/client/sidebar/header/MatrixFederationSearch/MatrixFederationRemoveServerList.tsx @@ -27,11 +27,15 @@ const MatrixFederationRemoveServerList = ({ servers }: MatrixFederationRemoveSer const queryClient = useQueryClient(); - const { mutate: removeServer, isLoading: isRemovingServer } = useMutation( - ['federation/removeServerByUser'], - (serverName: string) => removeMatrixServer({ serverName }), - { onSuccess: () => queryClient.invalidateQueries(['federation/listServersByUsers']) }, - ); + const { mutate: removeServer, isPending: isRemovingServer } = useMutation({ + mutationKey: ['federation/removeServerByUser'], + mutationFn: (serverName: string) => removeMatrixServer({ serverName }), + + onSuccess: () => + queryClient.invalidateQueries({ + queryKey: ['federation/listServersByUsers'], + }), + }); const t = useTranslation(); diff --git a/apps/meteor/client/sidebar/header/MatrixFederationSearch/useInfiniteFederationSearchPublicRooms.tsx b/apps/meteor/client/sidebar/header/MatrixFederationSearch/useInfiniteFederationSearchPublicRooms.tsx index 6d80a7a9b383..66336fe40058 100644 --- a/apps/meteor/client/sidebar/header/MatrixFederationSearch/useInfiniteFederationSearchPublicRooms.tsx +++ b/apps/meteor/client/sidebar/header/MatrixFederationSearch/useInfiniteFederationSearchPublicRooms.tsx @@ -5,14 +5,13 @@ const tenMinutes = 10 * 60 * 1000; export const useInfiniteFederationSearchPublicRooms = (serverName: string, roomName?: string, count?: number) => { const fetchRoomList = useEndpoint('GET', '/v1/federation/searchPublicRooms'); - return useInfiniteQuery( - ['federation/searchPublicRooms', serverName, roomName, count], - async ({ pageParam }) => fetchRoomList({ serverName, roomName, count, pageToken: pageParam }), - { - getNextPageParam: (lastPage) => lastPage.nextPageToken, - useErrorBoundary: true, - staleTime: tenMinutes, - cacheTime: tenMinutes, - }, - ); + return useInfiniteQuery({ + queryKey: ['federation/searchPublicRooms', serverName, roomName, count], + queryFn: async ({ pageParam }) => fetchRoomList({ serverName, roomName, count, pageToken: pageParam }), + getNextPageParam: (lastPage) => lastPage.nextPageToken, + initialPageParam: '', + throwOnError: true, + staleTime: tenMinutes, + gcTime: tenMinutes, + }); }; diff --git a/apps/meteor/client/sidebar/header/MatrixFederationSearch/useMatrixServerList.ts b/apps/meteor/client/sidebar/header/MatrixFederationSearch/useMatrixServerList.ts index 4f9ba64848f3..7ffa3d937bba 100644 --- a/apps/meteor/client/sidebar/header/MatrixFederationSearch/useMatrixServerList.ts +++ b/apps/meteor/client/sidebar/header/MatrixFederationSearch/useMatrixServerList.ts @@ -3,8 +3,10 @@ import { useQuery } from '@tanstack/react-query'; export const useMatrixServerList = () => { const fetchServerList = useEndpoint('GET', '/v1/federation/listServersByUser'); - return useQuery(['federation/listServersByUsers'], async () => fetchServerList(), { - useErrorBoundary: true, + return useQuery({ + queryKey: ['federation/listServersByUsers'], + queryFn: async () => fetchServerList(), + throwOnError: true, staleTime: Infinity, }); }; diff --git a/apps/meteor/client/sidebar/header/actions/Directory.tsx b/apps/meteor/client/sidebar/header/actions/Directory.tsx index 78a6b1756f19..66774659427e 100644 --- a/apps/meteor/client/sidebar/header/actions/Directory.tsx +++ b/apps/meteor/client/sidebar/header/actions/Directory.tsx @@ -1,5 +1,5 @@ import { Sidebar } from '@rocket.chat/fuselage'; -import { useMutableCallback } from '@rocket.chat/fuselage-hooks'; +import { useEffectEvent } from '@rocket.chat/fuselage-hooks'; import { useLayout, useRouter, useCurrentRoutePath } from '@rocket.chat/ui-contexts'; import type { HTMLAttributes } from 'react'; @@ -8,7 +8,7 @@ type DirectoryProps = Omit, 'is'>; const Directory = (props: DirectoryProps) => { const router = useRouter(); const { sidebar } = useLayout(); - const handleDirectory = useMutableCallback(() => { + const handleDirectory = useEffectEvent(() => { sidebar.toggle(); router.navigate('/directory'); }); diff --git a/apps/meteor/client/sidebar/header/actions/Home.tsx b/apps/meteor/client/sidebar/header/actions/Home.tsx index 5cfd307e7b32..5d6cc401078a 100644 --- a/apps/meteor/client/sidebar/header/actions/Home.tsx +++ b/apps/meteor/client/sidebar/header/actions/Home.tsx @@ -1,5 +1,5 @@ import { Sidebar } from '@rocket.chat/fuselage'; -import { useMutableCallback } from '@rocket.chat/fuselage-hooks'; +import { useEffectEvent } from '@rocket.chat/fuselage-hooks'; import { useRouter, useLayout, useSetting, useCurrentRoutePath } from '@rocket.chat/ui-contexts'; import type { HTMLAttributes } from 'react'; @@ -9,7 +9,7 @@ const SidebarHeaderActionHome = (props: SidebarHeaderActionHomeProps) => { const router = useRouter(); const { sidebar } = useLayout(); const showHome = useSetting('Layout_Show_Home_Button'); - const handleHome = useMutableCallback(() => { + const handleHome = useEffectEvent(() => { sidebar.toggle(); router.navigate('/home'); }); diff --git a/apps/meteor/client/sidebar/header/actions/Search.tsx b/apps/meteor/client/sidebar/header/actions/Search.tsx index d7f515e19fc0..3c5ce3dc61ea 100644 --- a/apps/meteor/client/sidebar/header/actions/Search.tsx +++ b/apps/meteor/client/sidebar/header/actions/Search.tsx @@ -1,5 +1,5 @@ import { Sidebar } from '@rocket.chat/fuselage'; -import { useMutableCallback, useOutsideClick } from '@rocket.chat/fuselage-hooks'; +import { useEffectEvent, useOutsideClick } from '@rocket.chat/fuselage-hooks'; import type { HTMLAttributes } from 'react'; import { useState, useEffect, useRef } from 'react'; import tinykeys from 'tinykeys'; @@ -12,13 +12,13 @@ const Search = (props: SearchProps) => { const [searchOpen, setSearchOpen] = useState(false); const ref = useRef(null); - const handleCloseSearch = useMutableCallback(() => { + const handleCloseSearch = useEffectEvent(() => { setSearchOpen(false); }); useOutsideClick([ref], handleCloseSearch); - const openSearch = useMutableCallback(() => { + const openSearch = useEffectEvent(() => { setSearchOpen(true); }); diff --git a/apps/meteor/client/sidebar/header/hooks/useAccountItems.tsx b/apps/meteor/client/sidebar/header/hooks/useAccountItems.tsx index ede1f8cb27f4..99100fdad2b5 100644 --- a/apps/meteor/client/sidebar/header/hooks/useAccountItems.tsx +++ b/apps/meteor/client/sidebar/header/hooks/useAccountItems.tsx @@ -1,5 +1,5 @@ import { Badge } from '@rocket.chat/fuselage'; -import { useMutableCallback } from '@rocket.chat/fuselage-hooks'; +import { useEffectEvent } from '@rocket.chat/fuselage-hooks'; import type { GenericMenuItemProps } from '@rocket.chat/ui-client'; import { defaultFeaturesPreview, usePreferenceFeaturePreviewList } from '@rocket.chat/ui-client'; import { useRouter } from '@rocket.chat/ui-contexts'; @@ -11,16 +11,16 @@ export const useAccountItems = (): GenericMenuItemProps[] => { const { unseenFeatures, featurePreviewEnabled } = usePreferenceFeaturePreviewList(); - const handleMyAccount = useMutableCallback(() => { + const handleMyAccount = useEffectEvent(() => { router.navigate('/account'); }); - const handlePreferences = useMutableCallback(() => { + const handlePreferences = useEffectEvent(() => { router.navigate('/account/preferences'); }); - const handleFeaturePreview = useMutableCallback(() => { + const handleFeaturePreview = useEffectEvent(() => { router.navigate('/account/feature-preview'); }); - const handleAccessibility = useMutableCallback(() => { + const handleAccessibility = useEffectEvent(() => { router.navigate('/account/accessibility-and-appearance'); }); diff --git a/apps/meteor/client/sidebar/header/hooks/useCreateRoomModal.tsx b/apps/meteor/client/sidebar/header/hooks/useCreateRoomModal.tsx index 38c858d0d6f5..4f64f1b8abcd 100644 --- a/apps/meteor/client/sidebar/header/hooks/useCreateRoomModal.tsx +++ b/apps/meteor/client/sidebar/header/hooks/useCreateRoomModal.tsx @@ -1,15 +1,15 @@ -import { useMutableCallback } from '@rocket.chat/fuselage-hooks'; +import { useEffectEvent } from '@rocket.chat/fuselage-hooks'; import { useSetModal } from '@rocket.chat/ui-contexts'; import type { ElementType } from 'react'; export const useCreateRoomModal = (Component: ElementType<{ onClose: () => void }>): (() => void) => { const setModal = useSetModal(); - return useMutableCallback(() => { + return useEffectEvent(() => { const handleClose = (): void => { setModal(null); }; - setModal(() => ); + setModal(); }); }; diff --git a/apps/meteor/client/sidebar/header/hooks/useUserMenu.tsx b/apps/meteor/client/sidebar/header/hooks/useUserMenu.tsx index c59f2ea85ebb..e31bad62e01f 100644 --- a/apps/meteor/client/sidebar/header/hooks/useUserMenu.tsx +++ b/apps/meteor/client/sidebar/header/hooks/useUserMenu.tsx @@ -1,5 +1,5 @@ import type { IUser } from '@rocket.chat/core-typings'; -import { useMutableCallback } from '@rocket.chat/fuselage-hooks'; +import { useEffectEvent } from '@rocket.chat/fuselage-hooks'; import type { GenericMenuItemProps } from '@rocket.chat/ui-client'; import { useLogout } from '@rocket.chat/ui-contexts'; import { useTranslation } from 'react-i18next'; @@ -17,7 +17,7 @@ export const useUserMenu = (user: IUser) => { const voipItemsSection = useVoipItemsSection(); const logout = useLogout(); - const handleLogout = useMutableCallback(() => { + const handleLogout = useEffectEvent(() => { logout(); }); diff --git a/apps/meteor/client/sidebar/header/hooks/useVoipItemsSection.tsx b/apps/meteor/client/sidebar/header/hooks/useVoipItemsSection.tsx index e70df6d66055..c8b7e89dd229 100644 --- a/apps/meteor/client/sidebar/header/hooks/useVoipItemsSection.tsx +++ b/apps/meteor/client/sidebar/header/hooks/useVoipItemsSection.tsx @@ -40,12 +40,12 @@ export const useVoipItemsSection = (): { items: GenericMenuItemProps[] } | undef return t(clientError.message); } - if (!isReady || toggleVoip.isLoading) { + if (!isReady || toggleVoip.isPending) { return t('Loading'); } return ''; - }, [clientError, isReady, toggleVoip.isLoading, t]); + }, [clientError, isReady, toggleVoip.isPending, t]); return useMemo(() => { if (!isEnabled) { @@ -57,7 +57,7 @@ export const useVoipItemsSection = (): { items: GenericMenuItemProps[] } | undef { id: 'toggle-voip', icon: isRegistered ? 'phone-disabled' : 'phone', - disabled: !isReady || toggleVoip.isLoading, + disabled: !isReady || toggleVoip.isPending, onClick: () => toggleVoip.mutate(), content: ( diff --git a/apps/meteor/client/sidebar/search/SearchList.tsx b/apps/meteor/client/sidebar/search/SearchList.tsx index 1c9230bf942d..25a865c28f13 100644 --- a/apps/meteor/client/sidebar/search/SearchList.tsx +++ b/apps/meteor/client/sidebar/search/SearchList.tsx @@ -1,7 +1,7 @@ import type { IRoom, ISubscription } from '@rocket.chat/core-typings'; import { css } from '@rocket.chat/css-in-js'; import { Sidebar, TextInput, Box, Icon } from '@rocket.chat/fuselage'; -import { useMutableCallback, useDebouncedValue, useAutoFocus, useUniqueId, useMergedRefs } from '@rocket.chat/fuselage-hooks'; +import { useEffectEvent, useDebouncedValue, useAutoFocus, useUniqueId, useMergedRefs } from '@rocket.chat/fuselage-hooks'; import { escapeRegExp } from '@rocket.chat/string-helpers'; import { useUserPreference, useUserSubscriptions, useSetting, useTranslation, useMethod } from '@rocket.chat/ui-contexts'; import type { UseQueryResult } from '@tanstack/react-query'; @@ -100,9 +100,10 @@ const useSearchItems = (filterText: string): UseQueryResult<(ISubscription & IRo const getSpotlight = useMethod('spotlight'); - return useQuery( - ['sidebar/search/spotlight', name, usernamesFromClient, type, localRooms.map(({ _id, name }) => _id + name)], - async () => { + return useQuery({ + queryKey: ['sidebar/search/spotlight', name, usernamesFromClient, type, localRooms.map(({ _id, name }) => _id + name)], + + queryFn: async () => { if (localRooms.length === LIMIT) { return localRooms; } @@ -157,17 +158,15 @@ const useSearchItems = (filterText: string): UseQueryResult<(ISubscription & IRo const exact = resultsFromServer?.filter((item) => [item.name, item.fname].includes(name)); return Array.from(new Set([...exact, ...localRooms, ...resultsFromServer])); }, - { - staleTime: 60_000, - keepPreviousData: true, - placeholderData: localRooms, - }, - ); + + staleTime: 60_000, + placeholderData: (previousData) => previousData ?? localRooms, + }); }; const useInput = (initial: string): { value: string; onChange: FormEventHandler; setValue: Dispatch> } => { const [value, setValue] = useState(initial); - const onChange = useMutableCallback((e) => { + const onChange = useEffectEvent((e) => { setValue(e.currentTarget.value); }); return { value, onChange, setValue }; @@ -232,7 +231,7 @@ const SearchList = forwardRef(function SearchList({ onClose }: SearchListProps, [avatarTemplate, extended, items, useRealName, sideBarItemTemplate, sidebarViewMode, t], ); - const changeSelection = useMutableCallback((dir) => { + const changeSelection = useEffectEvent((dir) => { let nextSelectedElement = null; if (dir === 'up') { @@ -254,7 +253,7 @@ const SearchList = forwardRef(function SearchList({ onClose }: SearchListProps, return selectedElement.current; }); - const resetCursor = useMutableCallback(() => { + const resetCursor = useEffectEvent(() => { setTimeout(() => { itemIndexRef.current = 0; listRef.current?.scrollToIndex({ index: itemIndexRef.current }); diff --git a/apps/meteor/client/sidebar/sections/OmnichannelSection.tsx b/apps/meteor/client/sidebar/sections/OmnichannelSection.tsx index 4616b4597af9..c5482119e7e0 100644 --- a/apps/meteor/client/sidebar/sections/OmnichannelSection.tsx +++ b/apps/meteor/client/sidebar/sections/OmnichannelSection.tsx @@ -1,5 +1,5 @@ import { Sidebar, SidebarDivider, SidebarSection } from '@rocket.chat/fuselage'; -import { useMutableCallback } from '@rocket.chat/fuselage-hooks'; +import { useEffectEvent } from '@rocket.chat/fuselage-hooks'; import { FeaturePreview, FeaturePreviewOff, FeaturePreviewOn } from '@rocket.chat/ui-client'; import { useLayout, useRoute, usePermission } from '@rocket.chat/ui-contexts'; import { memo } from 'react'; @@ -23,7 +23,7 @@ const OmnichannelSection = () => { const queueListRoute = useRoute('livechat-queue'); const isWorkspaceOverMacLimit = useIsOverMacLimit(); - const handleRoute = useMutableCallback((route) => { + const handleRoute = useEffectEvent((route) => { sidebar.toggle(); switch (route) { diff --git a/apps/meteor/client/sidebar/sections/actions/OmnichannelLivechatToggle.tsx b/apps/meteor/client/sidebar/sections/actions/OmnichannelLivechatToggle.tsx index 639aea178ae3..961996296d4e 100644 --- a/apps/meteor/client/sidebar/sections/actions/OmnichannelLivechatToggle.tsx +++ b/apps/meteor/client/sidebar/sections/actions/OmnichannelLivechatToggle.tsx @@ -1,5 +1,5 @@ import { Sidebar } from '@rocket.chat/fuselage'; -import { useMutableCallback } from '@rocket.chat/fuselage-hooks'; +import { useEffectEvent } from '@rocket.chat/fuselage-hooks'; import { useEndpoint, useToastMessageDispatch } from '@rocket.chat/ui-contexts'; import type { ReactElement, ComponentProps } from 'react'; import { useTranslation } from 'react-i18next'; @@ -12,7 +12,7 @@ export const OmnichannelLivechatToggle = (props: Omit { + const handleAvailableStatusChange = useEffectEvent(async () => { try { await changeAgentStatus({}); } catch (error: unknown) { diff --git a/apps/meteor/client/sidebarv2/RoomMenu.tsx b/apps/meteor/client/sidebarv2/RoomMenu.tsx index af7de006dc42..f74a231c613f 100644 --- a/apps/meteor/client/sidebarv2/RoomMenu.tsx +++ b/apps/meteor/client/sidebarv2/RoomMenu.tsx @@ -131,7 +131,9 @@ const RoomMenu = ({ const handleToggleRead = useEffectEvent(async () => { try { - queryClient.invalidateQueries(['sidebar/search/spotlight']); + queryClient.invalidateQueries({ + queryKey: ['sidebar/search/spotlight'], + }); if (isUnread) { await readMessages({ rid, readThreads: true }); diff --git a/apps/meteor/client/sidebarv2/footer/SidebarFooterWatermark.tsx b/apps/meteor/client/sidebarv2/footer/SidebarFooterWatermark.tsx index 36a7657177c0..850f2160e1ad 100644 --- a/apps/meteor/client/sidebarv2/footer/SidebarFooterWatermark.tsx +++ b/apps/meteor/client/sidebarv2/footer/SidebarFooterWatermark.tsx @@ -21,7 +21,7 @@ export const SidebarFooterWatermark = (): ReactElement | null => { const license = response.data; - if (license.activeModules.includes('hide-watermark') && !license.trial) { + if (license?.activeModules.includes('hide-watermark') && !license.trial) { return null; } diff --git a/apps/meteor/client/sidebarv2/footer/voip/hooks/useOmnichannelContactLabel.ts b/apps/meteor/client/sidebarv2/footer/voip/hooks/useOmnichannelContactLabel.ts index 6b3d59830d1e..ded2b9021d78 100644 --- a/apps/meteor/client/sidebarv2/footer/voip/hooks/useOmnichannelContactLabel.ts +++ b/apps/meteor/client/sidebarv2/footer/voip/hooks/useOmnichannelContactLabel.ts @@ -8,7 +8,9 @@ export const useOmnichannelContactLabel = (caller: ICallerInfo): string => { const getContactBy = useEndpoint('GET', '/v1/omnichannel/contact.search'); const phone = parseOutboundPhoneNumber(caller.callerId); - const { data } = useQuery(['getContactsByPhone', phone], async () => getContactBy({ phone }).then(({ contact }) => contact), { + const { data } = useQuery({ + queryKey: ['getContactsByPhone', phone], + queryFn: async () => getContactBy({ phone }).then(({ contact }) => contact), enabled: !!phone, }); diff --git a/apps/meteor/client/sidebarv2/header/MatrixFederationSearch/FederatedRoomList.tsx b/apps/meteor/client/sidebarv2/header/MatrixFederationSearch/FederatedRoomList.tsx index 50f2fa007088..50bdb8018486 100644 --- a/apps/meteor/client/sidebarv2/header/MatrixFederationSearch/FederatedRoomList.tsx +++ b/apps/meteor/client/sidebarv2/header/MatrixFederationSearch/FederatedRoomList.tsx @@ -24,36 +24,37 @@ const FederatedRoomList = ({ serverName, roomName, count }: FederatedRoomListPro const setModal = useSetModal(); const { t } = useTranslation(); const dispatchToastMessage = useToastMessageDispatch(); - const { data, isLoading, isFetchingNextPage, fetchNextPage } = useInfiniteFederationSearchPublicRooms(serverName, roomName, count); + const { data, isPending, isFetchingNextPage, fetchNextPage } = useInfiniteFederationSearchPublicRooms(serverName, roomName, count); - const { mutate: onClickJoin, isLoading: isLoadingMutation } = useMutation( - ['federation/joinExternalPublicRoom'], - async ({ id, pageToken }: IFederationPublicRooms) => { + const { mutate: onClickJoin, isPending: isLoadingMutation } = useMutation({ + mutationKey: ['federation/joinExternalPublicRoom'], + + mutationFn: async ({ id, pageToken }: IFederationPublicRooms) => { return joinExternalPublicRoom({ externalRoomId: id as `!${string}:${string}`, roomName, pageToken }); }, - { - onSuccess: (_, data) => { - dispatchToastMessage({ - type: 'success', - message: t('Your_request_to_join__roomName__has_been_made_it_could_take_up_to_15_minutes_to_be_processed', { - roomName: data.name, - }), - }); + + onSuccess: (_, data) => { + dispatchToastMessage({ + type: 'success', + message: t('Your_request_to_join__roomName__has_been_made_it_could_take_up_to_15_minutes_to_be_processed', { + roomName: data.name, + }), + }); + setModal(null); + }, + + onError: (error, { id }) => { + if (error instanceof Error && error.message === 'already-joined') { setModal(null); - }, - onError: (error, { id }) => { - if (error instanceof Error && error.message === 'already-joined') { - setModal(null); - roomCoordinator.openRouteLink('c', { rid: id }); - return; - } + roomCoordinator.openRouteLink('c', { rid: id }); + return; + } - dispatchToastMessage({ type: 'error', message: error }); - }, + dispatchToastMessage({ type: 'error', message: error }); }, - ); + }); - if (isLoading) { + if (isPending) { return ; } @@ -70,7 +71,7 @@ const FederatedRoomList = ({ serverName, roomName, count }: FederatedRoomListPro Scroller: VirtuosoScrollbars, EmptyPlaceholder: FederatedRoomListEmptyPlaceholder, }} - endReached={isLoading || isFetchingNextPage ? () => undefined : () => fetchNextPage()} + endReached={isPending || isFetchingNextPage ? () => undefined : () => fetchNextPage()} itemContent={(_, room) => ( onClickJoin(room)} {...room} disabled={isLoadingMutation} key={room.id} /> )} diff --git a/apps/meteor/client/sidebarv2/header/MatrixFederationSearch/MatrixFederationManageServerModal.tsx b/apps/meteor/client/sidebarv2/header/MatrixFederationSearch/MatrixFederationManageServerModal.tsx index 13a761c0cac6..dd0d15e11131 100644 --- a/apps/meteor/client/sidebarv2/header/MatrixFederationSearch/MatrixFederationManageServerModal.tsx +++ b/apps/meteor/client/sidebarv2/header/MatrixFederationSearch/MatrixFederationManageServerModal.tsx @@ -36,13 +36,19 @@ const MatrixFederationAddServerModal = ({ onClickClose }: MatrixFederationAddSer const { mutate: addServer, - isLoading, + isPending, isError, - } = useMutation(['v1/federation/addServerByUser', serverName], () => addMatrixServer({ serverName }), { + } = useMutation({ + mutationKey: ['v1/federation/addServerByUser', serverName], + mutationFn: () => addMatrixServer({ serverName }), + onSuccess: async () => { - await queryClient.invalidateQueries(['federation/listServersByUsers']); + await queryClient.invalidateQueries({ + queryKey: ['federation/listServersByUsers'], + }); setModal(); }, + onError: (error) => { const errorKey = getErrorKey(error); if (!errorKey) { @@ -53,7 +59,7 @@ const MatrixFederationAddServerModal = ({ onClickClose }: MatrixFederationAddSer }, }); - const { data, isLoading: isLoadingServerList } = useMatrixServerList(); + const { data, isPending: isLoadingServerList } = useMatrixServerList(); return ( @@ -66,7 +72,7 @@ const MatrixFederationAddServerModal = ({ onClickClose }: MatrixFederationAddSer {t('Server_name')} ) => { setServerName(e.currentTarget.value); @@ -76,7 +82,7 @@ const MatrixFederationAddServerModal = ({ onClickClose }: MatrixFederationAddSer }} mie={4} /> - diff --git a/apps/meteor/client/sidebarv2/header/MatrixFederationSearch/MatrixFederationRemoveServerList.tsx b/apps/meteor/client/sidebarv2/header/MatrixFederationSearch/MatrixFederationRemoveServerList.tsx index 073d7976ca94..2531be96e6f0 100644 --- a/apps/meteor/client/sidebarv2/header/MatrixFederationSearch/MatrixFederationRemoveServerList.tsx +++ b/apps/meteor/client/sidebarv2/header/MatrixFederationSearch/MatrixFederationRemoveServerList.tsx @@ -27,11 +27,15 @@ const MatrixFederationRemoveServerList = ({ servers }: MatrixFederationRemoveSer const queryClient = useQueryClient(); - const { mutate: removeServer, isLoading: isRemovingServer } = useMutation( - ['federation/removeServerByUser'], - (serverName: string) => removeMatrixServer({ serverName }), - { onSuccess: () => queryClient.invalidateQueries(['federation/listServersByUsers']) }, - ); + const { mutate: removeServer, isPending: isRemovingServer } = useMutation({ + mutationKey: ['federation/removeServerByUser'], + mutationFn: (serverName: string) => removeMatrixServer({ serverName }), + + onSuccess: () => + queryClient.invalidateQueries({ + queryKey: ['federation/listServersByUsers'], + }), + }); const t = useTranslation(); diff --git a/apps/meteor/client/sidebarv2/header/MatrixFederationSearch/useInfiniteFederationSearchPublicRooms.ts b/apps/meteor/client/sidebarv2/header/MatrixFederationSearch/useInfiniteFederationSearchPublicRooms.ts index 6d80a7a9b383..66336fe40058 100644 --- a/apps/meteor/client/sidebarv2/header/MatrixFederationSearch/useInfiniteFederationSearchPublicRooms.ts +++ b/apps/meteor/client/sidebarv2/header/MatrixFederationSearch/useInfiniteFederationSearchPublicRooms.ts @@ -5,14 +5,13 @@ const tenMinutes = 10 * 60 * 1000; export const useInfiniteFederationSearchPublicRooms = (serverName: string, roomName?: string, count?: number) => { const fetchRoomList = useEndpoint('GET', '/v1/federation/searchPublicRooms'); - return useInfiniteQuery( - ['federation/searchPublicRooms', serverName, roomName, count], - async ({ pageParam }) => fetchRoomList({ serverName, roomName, count, pageToken: pageParam }), - { - getNextPageParam: (lastPage) => lastPage.nextPageToken, - useErrorBoundary: true, - staleTime: tenMinutes, - cacheTime: tenMinutes, - }, - ); + return useInfiniteQuery({ + queryKey: ['federation/searchPublicRooms', serverName, roomName, count], + queryFn: async ({ pageParam }) => fetchRoomList({ serverName, roomName, count, pageToken: pageParam }), + getNextPageParam: (lastPage) => lastPage.nextPageToken, + initialPageParam: '', + throwOnError: true, + staleTime: tenMinutes, + gcTime: tenMinutes, + }); }; diff --git a/apps/meteor/client/sidebarv2/header/MatrixFederationSearch/useMatrixServerList.ts b/apps/meteor/client/sidebarv2/header/MatrixFederationSearch/useMatrixServerList.ts index 4f9ba64848f3..7ffa3d937bba 100644 --- a/apps/meteor/client/sidebarv2/header/MatrixFederationSearch/useMatrixServerList.ts +++ b/apps/meteor/client/sidebarv2/header/MatrixFederationSearch/useMatrixServerList.ts @@ -3,8 +3,10 @@ import { useQuery } from '@tanstack/react-query'; export const useMatrixServerList = () => { const fetchServerList = useEndpoint('GET', '/v1/federation/listServersByUser'); - return useQuery(['federation/listServersByUsers'], async () => fetchServerList(), { - useErrorBoundary: true, + return useQuery({ + queryKey: ['federation/listServersByUsers'], + queryFn: async () => fetchServerList(), + throwOnError: true, staleTime: Infinity, }); }; diff --git a/apps/meteor/client/sidebarv2/header/hooks/useCreateRoomModal.tsx b/apps/meteor/client/sidebarv2/header/hooks/useCreateRoomModal.tsx index a5e26cf8227b..d1af9eb35599 100644 --- a/apps/meteor/client/sidebarv2/header/hooks/useCreateRoomModal.tsx +++ b/apps/meteor/client/sidebarv2/header/hooks/useCreateRoomModal.tsx @@ -10,6 +10,6 @@ export const useCreateRoomModal = (Component: FC): (() => void) => { setModal(null); }; - setModal(() => ); + setModal(); }); }; diff --git a/apps/meteor/client/sidebarv2/header/hooks/useSearchItems.ts b/apps/meteor/client/sidebarv2/header/hooks/useSearchItems.ts index cc7bf02249b7..a44dceeb2f8f 100644 --- a/apps/meteor/client/sidebarv2/header/hooks/useSearchItems.ts +++ b/apps/meteor/client/sidebarv2/header/hooks/useSearchItems.ts @@ -16,6 +16,7 @@ const options = { limit: LIMIT, } as const; +// FIXME: the return type is UTTERLY wrong, but I'm not sure what it should be export const useSearchItems = (filterText: string): UseQueryResult => { const [, mention, name] = useMemo(() => filterText.match(/(@|#)?(.*)/i) || [], [filterText]); const query = useMemo(() => { @@ -48,9 +49,10 @@ export const useSearchItems = (filterText: string): UseQueryResult _id + name)], - async () => { + return useQuery({ + queryKey: ['sidebar/search/spotlight', name, usernamesFromClient, type, localRooms.map(({ _id, name }) => _id + name)], + + queryFn: async () => { if (localRooms.length === LIMIT) { return localRooms; } @@ -105,10 +107,8 @@ export const useSearchItems = (filterText: string): UseQueryResult [item.name, item.fname].includes(name)); return Array.from(new Set([...exact, ...localRooms, ...resultsFromServer])); }, - { - staleTime: 60_000, - keepPreviousData: true, - placeholderData: localRooms, - }, - ); + + staleTime: 60_000, + placeholderData: (previousData) => previousData ?? localRooms, + }); }; diff --git a/apps/meteor/client/stories/contexts/QueryClientProviderMock.tsx b/apps/meteor/client/stories/contexts/QueryClientProviderMock.tsx index cb16201e3a21..b1cecf148ade 100644 --- a/apps/meteor/client/stories/contexts/QueryClientProviderMock.tsx +++ b/apps/meteor/client/stories/contexts/QueryClientProviderMock.tsx @@ -1,25 +1,43 @@ -import { QueryCache, QueryClient, QueryClientProvider } from '@tanstack/react-query'; +import type { DefaultError, Query } from '@tanstack/react-query'; +import { QueryClient, QueryClientProvider } from '@tanstack/react-query'; import type { ReactNode } from 'react'; -const queryCache = new QueryCache(); +import { dispatchToastMessage } from '../../lib/toast'; const queryClient = new QueryClient({ defaultOptions: { queries: { retry: false, - cacheTime: Infinity, + gcTime: Infinity, refetchOnWindowFocus: false, }, }, - queryCache, }); type QueryClientProviderMockProps = { children?: ReactNode; }; -const QueryClientProviderMock = ({ children }: QueryClientProviderMockProps) => ( - {children} -); +const QueryClientProviderMock = ({ children }: QueryClientProviderMockProps) => { + const queryCacheInstance = queryClient.getQueryCache(); + + queryCacheInstance.config.onError = (error: DefaultError, query: Query) => { + const { errorToastMessage, apiErrorToastMessage } = query?.meta as { errorToastMessage?: string; apiErrorToastMessage?: boolean }; + if (apiErrorToastMessage) { + dispatchToastMessage({ type: 'error', message: error }); + } else if (errorToastMessage) { + dispatchToastMessage({ type: 'error', message: errorToastMessage }); + } + }; + + queryCacheInstance.config.onSuccess = (_, query: Query) => { + const { successToastMessage } = query?.meta as { successToastMessage?: string }; + if (successToastMessage) { + dispatchToastMessage({ type: 'success', message: successToastMessage }); + } + }; + + return {children}; +}; export default QueryClientProviderMock; diff --git a/apps/meteor/client/uikit/hooks/useMessageBlockContextValue.ts b/apps/meteor/client/uikit/hooks/useMessageBlockContextValue.ts index caf869ba39d7..b99b7eb0f1b4 100644 --- a/apps/meteor/client/uikit/hooks/useMessageBlockContextValue.ts +++ b/apps/meteor/client/uikit/hooks/useMessageBlockContextValue.ts @@ -1,5 +1,5 @@ import type { IRoom, IMessage } from '@rocket.chat/core-typings'; -import { useMutableCallback } from '@rocket.chat/fuselage-hooks'; +import { useEffectEvent } from '@rocket.chat/fuselage-hooks'; import type { UiKitContext } from '@rocket.chat/fuselage-ui-kit'; import type { ContextType } from 'react'; @@ -24,7 +24,7 @@ export const useMessageBlockContextValue = (rid: IRoom['_id'], mid: IMessage['_i const videoConfManager = useVideoConfManager(); - const handleOpenVideoConf = useMutableCallback(async (rid: IRoom['_id']) => { + const handleOpenVideoConf = useEffectEvent(async (rid: IRoom['_id']) => { if (isCalling || isRinging) { return; } diff --git a/apps/meteor/client/views/account/preferences/PreferencesMyDataSection.tsx b/apps/meteor/client/views/account/preferences/PreferencesMyDataSection.tsx index 00b1d0301eba..53e91211a49d 100644 --- a/apps/meteor/client/views/account/preferences/PreferencesMyDataSection.tsx +++ b/apps/meteor/client/views/account/preferences/PreferencesMyDataSection.tsx @@ -13,7 +13,7 @@ const PreferencesMyDataSection = () => { const requestDataDownload = useMethod('requestDataDownload'); const downloadData = useCallback( - async (fullExport) => { + async (fullExport: boolean) => { try { const result = await requestDataDownload({ fullExport }); if (result.requested) { diff --git a/apps/meteor/client/views/account/profile/AccountProfilePage.tsx b/apps/meteor/client/views/account/profile/AccountProfilePage.tsx index 730ff507e545..bc8a267165f7 100644 --- a/apps/meteor/client/views/account/profile/AccountProfilePage.tsx +++ b/apps/meteor/client/views/account/profile/AccountProfilePage.tsx @@ -76,7 +76,7 @@ const AccountProfilePage = (): ReactElement => { } }; - return setModal(() => ( + return setModal( setModal(null)} @@ -84,8 +84,8 @@ const AccountProfilePage = (): ReactElement => { confirmText={t('Delete')} shouldChangeOwner={shouldChangeOwner} shouldBeRemoved={shouldBeRemoved} - /> - )); + />, + ); }, [erasureType, setModal, t, deleteOwnAccount, dispatchToastMessage, logout], ); @@ -106,7 +106,7 @@ const AccountProfilePage = (): ReactElement => { } }; - return setModal(() => setModal(null)} isPassword={hasLocalPassword} />); + return setModal( setModal(null)} isPassword={hasLocalPassword} />); }, [dispatchToastMessage, hasLocalPassword, setModal, handleConfirmOwnerChange, deleteOwnAccount, logout, t]); const profileFormId = useUniqueId(); diff --git a/apps/meteor/client/views/account/security/TwoFactorTOTP.tsx b/apps/meteor/client/views/account/security/TwoFactorTOTP.tsx index 7ada0c88a6f0..cc282c2ba64e 100644 --- a/apps/meteor/client/views/account/security/TwoFactorTOTP.tsx +++ b/apps/meteor/client/views/account/security/TwoFactorTOTP.tsx @@ -1,7 +1,7 @@ import { Box, Button, TextInput, Margins } from '@rocket.chat/fuselage'; import { useSafely } from '@rocket.chat/fuselage-hooks'; import { useSetModal, useToastMessageDispatch, useUser, useMethod } from '@rocket.chat/ui-contexts'; -import type { ReactElement, ComponentProps } from 'react'; +import type { ReactElement, ComponentPropsWithoutRef } from 'react'; import { useState, useCallback, useEffect } from 'react'; import { useForm } from 'react-hook-form'; import { useTranslation } from 'react-i18next'; @@ -11,7 +11,13 @@ import BackupCodesModal from './BackupCodesModal'; import TextCopy from '../../../components/TextCopy'; import TwoFactorTotpModal from '../../../components/TwoFactorModal/TwoFactorTotpModal'; -const TwoFactorTOTP = (props: ComponentProps): ReactElement => { +type TwoFactorTOTPFormData = { + authCode: string; +}; + +type TwoFactorTOTPProps = ComponentPropsWithoutRef; + +const TwoFactorTOTP = (props: TwoFactorTOTPProps): ReactElement => { const { t } = useTranslation(); const dispatchToastMessage = useToastMessageDispatch(); const user = useUser(); @@ -28,7 +34,7 @@ const TwoFactorTOTP = (props: ComponentProps): ReactElement => { const [totpSecret, setTotpSecret] = useSafely(useState()); const [codesRemaining, setCodesRemaining] = useSafely(useState(0)); - const { register, handleSubmit } = useForm({ defaultValues: { authCode: '' } }); + const { register, handleSubmit } = useForm({ defaultValues: { authCode: '' } }); const totpEnabled = user?.services?.totp?.enabled; @@ -78,7 +84,7 @@ const TwoFactorTOTP = (props: ComponentProps): ReactElement => { }, [closeModal, disableTotpFn, dispatchToastMessage, setModal, t]); const handleVerifyCode = useCallback( - async ({ authCode }) => { + async ({ authCode }: TwoFactorTOTPFormData) => { try { const result = await verifyCodeFn(authCode); diff --git a/apps/meteor/client/views/account/tokens/AccountTokensTable/AddToken.tsx b/apps/meteor/client/views/account/tokens/AccountTokensTable/AddToken.tsx index b5cd7764f51c..a4d6ef483ca5 100644 --- a/apps/meteor/client/views/account/tokens/AccountTokensTable/AddToken.tsx +++ b/apps/meteor/client/views/account/tokens/AccountTokensTable/AddToken.tsx @@ -1,14 +1,22 @@ import type { SelectOption } from '@rocket.chat/fuselage'; import { Box, TextInput, Button, Margins, Select } from '@rocket.chat/fuselage'; import { useSetModal, useToastMessageDispatch, useUserId, useMethod } from '@rocket.chat/ui-contexts'; -import type { ReactElement } from 'react'; import { useCallback, useMemo, useEffect } from 'react'; import { Controller, useForm } from 'react-hook-form'; import { useTranslation } from 'react-i18next'; import GenericModal from '../../../../components/GenericModal'; -const AddToken = ({ reload }: { reload: () => void }): ReactElement => { +type AddTokenFormData = { + name: string; + bypassTwoFactor: string; +}; + +type AddTokenProps = { + reload: () => void; +}; + +const AddToken = ({ reload }: AddTokenProps) => { const { t } = useTranslation(); const userId = useUserId(); const setModal = useSetModal(); @@ -23,7 +31,7 @@ const AddToken = ({ reload }: { reload: () => void }): ReactElement => { handleSubmit, control, formState: { isSubmitted, submitCount }, - } = useForm({ defaultValues: initialValues }); + } = useForm({ defaultValues: initialValues }); const twoFactorAuthOptions: SelectOption[] = useMemo( () => [ @@ -34,7 +42,7 @@ const AddToken = ({ reload }: { reload: () => void }): ReactElement => { ); const handleAddToken = useCallback( - async ({ name: tokenName, bypassTwoFactor }) => { + async ({ name: tokenName, bypassTwoFactor }: AddTokenFormData) => { try { const token = await createTokenFn({ tokenName, bypassTwoFactor: bypassTwoFactor === 'bypass' }); diff --git a/apps/meteor/client/views/admin/customEmoji/AddCustomEmoji.tsx b/apps/meteor/client/views/admin/customEmoji/AddCustomEmoji.tsx index 5f22238a1c2a..bf423e53cf99 100644 --- a/apps/meteor/client/views/admin/customEmoji/AddCustomEmoji.tsx +++ b/apps/meteor/client/views/admin/customEmoji/AddCustomEmoji.tsx @@ -21,7 +21,7 @@ const AddCustomEmoji = ({ close, onChange, ...props }: AddCustomEmojiProps): Rea const [errors, setErrors] = useState({ name: false, emoji: false, aliases: false }); const setEmojiPreview = useCallback( - async (file) => { + async (file: Blob) => { setEmojiFile(file); setNewEmojiPreview(URL.createObjectURL(file)); setErrors((prevState) => ({ ...prevState, emoji: false })); diff --git a/apps/meteor/client/views/admin/customEmoji/CustomEmoji.tsx b/apps/meteor/client/views/admin/customEmoji/CustomEmoji.tsx index 5d486c28cb3d..66829705f5b7 100644 --- a/apps/meteor/client/views/admin/customEmoji/CustomEmoji.tsx +++ b/apps/meteor/client/views/admin/customEmoji/CustomEmoji.tsx @@ -58,7 +58,10 @@ const CustomEmoji = ({ onClick, reload }: CustomEmojiProps) => { ); const getEmojiList = useEndpoint('GET', '/v1/emoji-custom.all'); - const { data, refetch, isSuccess, isLoading, isError } = useQuery(['getEmojiList', query], () => getEmojiList(query)); + const { data, refetch, isSuccess, isLoading, isError } = useQuery({ + queryKey: ['getEmojiList', query], + queryFn: () => getEmojiList(query), + }); useEffect(() => { reload.current = refetch; diff --git a/apps/meteor/client/views/admin/customEmoji/EditCustomEmoji.tsx b/apps/meteor/client/views/admin/customEmoji/EditCustomEmoji.tsx index 16ac6670d5bb..431f5671aeff 100644 --- a/apps/meteor/client/views/admin/customEmoji/EditCustomEmoji.tsx +++ b/apps/meteor/client/views/admin/customEmoji/EditCustomEmoji.tsx @@ -115,11 +115,11 @@ const EditCustomEmoji = ({ close, onChange, data, ...props }: EditCustomEmojiPro setModal(null); }; - setModal(() => ( + setModal( {t('Custom_Emoji_Delete_Warning')} - - )); + , + ); }, [setModal, deleteAction, _id, dispatchToastMessage, t, onChange, close]); const handleChangeAliases = useCallback( diff --git a/apps/meteor/client/views/admin/customEmoji/EditCustomEmojiWithData.tsx b/apps/meteor/client/views/admin/customEmoji/EditCustomEmojiWithData.tsx index 72801a373aea..a593e67333c7 100644 --- a/apps/meteor/client/views/admin/customEmoji/EditCustomEmojiWithData.tsx +++ b/apps/meteor/client/views/admin/customEmoji/EditCustomEmojiWithData.tsx @@ -19,12 +19,16 @@ const EditCustomEmojiWithData = ({ _id, onChange, close, ...props }: EditCustomE const getEmojis = useEndpoint('GET', '/v1/emoji-custom.list'); - const { data, isLoading, error, refetch } = useQuery(['custom-emojis', query], async () => { - const emoji = await getEmojis(query); - return emoji; + const { data, isPending, error, refetch } = useQuery({ + queryKey: ['custom-emojis', query], + + queryFn: async () => { + const emoji = await getEmojis(query); + return emoji; + }, }); - if (isLoading) { + if (isPending) { return ; } diff --git a/apps/meteor/client/views/admin/customSounds/AddCustomSound.tsx b/apps/meteor/client/views/admin/customSounds/AddCustomSound.tsx index 2d5e392d4ff7..71d1495c1f70 100644 --- a/apps/meteor/client/views/admin/customSounds/AddCustomSound.tsx +++ b/apps/meteor/client/views/admin/customSounds/AddCustomSound.tsx @@ -31,7 +31,8 @@ const AddCustomSound = ({ goToNew, close, onChange, ...props }: AddCustomSoundPr const [clickUpload] = useSingleFileInput(handleChangeFile, 'audio/mp3'); const saveAction = useCallback( - async (name, soundFile): Promise => { + // FIXME + async (name: string, soundFile: any) => { const soundData = createSoundData(soundFile, name); const validation = validate(soundData, soundFile) as Array[0]>; diff --git a/apps/meteor/client/views/admin/customSounds/CustomSoundsTable/CustomSoundsTable.tsx b/apps/meteor/client/views/admin/customSounds/CustomSoundsTable/CustomSoundsTable.tsx index 91e988e0acbf..7a70ec984815 100644 --- a/apps/meteor/client/views/admin/customSounds/CustomSoundsTable/CustomSoundsTable.tsx +++ b/apps/meteor/client/views/admin/customSounds/CustomSoundsTable/CustomSoundsTable.tsx @@ -44,7 +44,9 @@ const CustomSoundsTable = ({ reload, onClick }: CustomSoundsTableProps) => { ); const getSounds = useEndpoint('GET', '/v1/custom-sounds.list'); - const { data, refetch, isLoading, isError, isSuccess } = useQuery(['custom-sounds', query], async () => getSounds(query), { + const { data, refetch, isLoading, isError, isSuccess } = useQuery({ + queryKey: ['custom-sounds', query], + queryFn: async () => getSounds(query), refetchOnMount: false, }); diff --git a/apps/meteor/client/views/admin/customSounds/EditCustomSound.tsx b/apps/meteor/client/views/admin/customSounds/EditCustomSound.tsx index 5eabbaa5e8cf..a16c6e476505 100644 --- a/apps/meteor/client/views/admin/customSounds/EditCustomSound.tsx +++ b/apps/meteor/client/views/admin/customSounds/EditCustomSound.tsx @@ -1,4 +1,4 @@ -import { useEndpoint, useToastMessageDispatch } from '@rocket.chat/ui-contexts'; +import { useEndpoint } from '@rocket.chat/ui-contexts'; import { useQuery } from '@tanstack/react-query'; import type { ReactElement } from 'react'; import { useTranslation } from 'react-i18next'; @@ -16,11 +16,10 @@ function EditCustomSound({ _id, onChange, ...props }: EditCustomSoundProps): Rea const { t } = useTranslation(); const getSounds = useEndpoint('GET', '/v1/custom-sounds.list'); - const dispatchToastMessage = useToastMessageDispatch(); + const { data, isPending, refetch } = useQuery({ + queryKey: ['custom-sounds', _id], - const { data, isLoading, refetch } = useQuery( - ['custom-sounds', _id], - async () => { + queryFn: async () => { const { sounds } = await getSounds({ query: JSON.stringify({ _id }) }); if (sounds.length === 0) { @@ -28,14 +27,10 @@ function EditCustomSound({ _id, onChange, ...props }: EditCustomSoundProps): Rea } return sounds[0]; }, - { - onError: (error) => { - dispatchToastMessage({ type: 'error', message: error }); - }, - }, - ); + meta: { apiErrorToastMessage: true }, + }); - if (isLoading) { + if (isPending) { return ; } diff --git a/apps/meteor/client/views/admin/customSounds/EditSound.tsx b/apps/meteor/client/views/admin/customSounds/EditSound.tsx index 2c0e82061b3d..beeb0d0be163 100644 --- a/apps/meteor/client/views/admin/customSounds/EditSound.tsx +++ b/apps/meteor/client/views/admin/customSounds/EditSound.tsx @@ -53,7 +53,8 @@ function EditSound({ close, onChange, data, ...props }: EditSoundProps): ReactEl const hasUnsavedChanges = useMemo(() => previousName !== name || previousSound !== sound, [name, previousName, previousSound, sound]); const saveAction = useCallback( - async (sound) => { + // FIXME + async (sound: any) => { const soundData = createSoundData(sound, name, { previousName, previousSound, _id, extension: sound.extension }); const validation = validate(soundData, sound); if (validation.length === 0) { @@ -115,11 +116,11 @@ function EditSound({ close, onChange, data, ...props }: EditSoundProps): ReactEl const handleCancel = (): void => setModal(null); - setModal(() => ( + setModal( {t('Custom_Sound_Delete_Warning')} - - )); + , + ); }, [_id, close, deleteCustomSound, dispatchToastMessage, onChange, setModal, t]); const [clickUpload] = useSingleFileInput(handleChangeFile, 'audio/mp3'); diff --git a/apps/meteor/client/views/admin/customUserStatus/CustomUserActiveConnections.tsx b/apps/meteor/client/views/admin/customUserStatus/CustomUserActiveConnections.tsx index 71c838435169..f82714f367d2 100644 --- a/apps/meteor/client/views/admin/customUserStatus/CustomUserActiveConnections.tsx +++ b/apps/meteor/client/views/admin/customUserStatus/CustomUserActiveConnections.tsx @@ -8,7 +8,7 @@ const CustomUserActiveConnections = () => { const result = useActiveConnections(); - if (result.isLoading || result.isError) { + if (result.isPending || result.isError) { return ; } diff --git a/apps/meteor/client/views/admin/customUserStatus/CustomUserStatusForm.tsx b/apps/meteor/client/views/admin/customUserStatus/CustomUserStatusForm.tsx index 22ad9517f338..99de03d6f975 100644 --- a/apps/meteor/client/views/admin/customUserStatus/CustomUserStatusForm.tsx +++ b/apps/meteor/client/views/admin/customUserStatus/CustomUserStatusForm.tsx @@ -10,6 +10,11 @@ import { useForm, Controller } from 'react-hook-form'; import { ContextualbarScrollableContent, ContextualbarFooter } from '../../../components/Contextualbar'; import GenericModal from '../../../components/GenericModal'; +type CustomUserStatusFormFormData = { + name: string; + statusType: string; +}; + type CustomUserStatusFormProps = { onClose: () => void; onReload: () => void; @@ -18,7 +23,7 @@ type CustomUserStatusFormProps = { const CustomUserStatusForm = ({ onClose, onReload, status }: CustomUserStatusFormProps): ReactElement => { const t = useTranslation(); - const { _id, name, statusType } = status || {}; + const { _id } = status || {}; const setModal = useSetModal(); const route = useRoute('user-status'); const dispatchToastMessage = useToastMessageDispatch(); @@ -29,18 +34,23 @@ const CustomUserStatusForm = ({ onClose, onReload, status }: CustomUserStatusFor control, handleSubmit, formState: { errors }, - } = useForm({ + } = useForm({ defaultValues: { name: status?.name ?? '', statusType: status?.statusType ?? '' }, mode: 'all', }); - const saveStatus = useEndpoint('POST', _id ? '/v1/custom-user-status.update' : '/v1/custom-user-status.create'); + const createStatus = useEndpoint('POST', '/v1/custom-user-status.create'); + const updateStatus = useEndpoint('POST', '/v1/custom-user-status.update'); const deleteStatus = useEndpoint('POST', '/v1/custom-user-status.delete'); const handleSave = useCallback( - async (data) => { + async (data: CustomUserStatusFormFormData) => { try { - await saveStatus({ _id, name, statusType, ...data }); + if (status?._id) { + await updateStatus({ _id: status?._id, ...data }); + } else { + await createStatus({ ...data }); + } dispatchToastMessage({ type: 'success', @@ -53,7 +63,7 @@ const CustomUserStatusForm = ({ onClose, onReload, status }: CustomUserStatusFor dispatchToastMessage({ type: 'error', message: error }); } }, - [saveStatus, _id, name, statusType, route, dispatchToastMessage, t, onReload], + [status?._id, dispatchToastMessage, t, onReload, route, updateStatus, createStatus], ); const handleDeleteStatus = useCallback(() => { @@ -63,7 +73,7 @@ const CustomUserStatusForm = ({ onClose, onReload, status }: CustomUserStatusFor const handleDelete = async (): Promise => { try { - await deleteStatus({ customUserStatusId: _id || '' }); + await deleteStatus({ customUserStatusId: status?._id ?? '' }); dispatchToastMessage({ type: 'success', message: t('Custom_User_Status_Has_Been_Deleted') }); onReload(); route.push({}); @@ -74,12 +84,12 @@ const CustomUserStatusForm = ({ onClose, onReload, status }: CustomUserStatusFor } }; - setModal(() => ( + setModal( {t('Custom_User_Status_Delete_Warning')} - - )); - }, [_id, route, deleteStatus, dispatchToastMessage, onReload, setModal, t]); + , + ); + }, [status?._id, route, deleteStatus, dispatchToastMessage, onReload, setModal, t]); const presenceOptions: SelectOption[] = [ ['online', t('Online')], diff --git a/apps/meteor/client/views/admin/customUserStatus/CustomUserStatusFormWithData.tsx b/apps/meteor/client/views/admin/customUserStatus/CustomUserStatusFormWithData.tsx index a9f42b7f8680..d033bb303ba4 100644 --- a/apps/meteor/client/views/admin/customUserStatus/CustomUserStatusFormWithData.tsx +++ b/apps/meteor/client/views/admin/customUserStatus/CustomUserStatusFormWithData.tsx @@ -21,9 +21,13 @@ const CustomUserStatusFormWithData = ({ _id, onReload, onClose }: CustomUserStat const getCustomUserStatus = useEndpoint('GET', '/v1/custom-user-status.list'); - const { data, isLoading, error, refetch } = useQuery(['custom-user-statuses', query], async () => { - const customUserStatus = await getCustomUserStatus(query); - return customUserStatus; + const { data, isPending, error, refetch } = useQuery({ + queryKey: ['custom-user-statuses', query], + + queryFn: async () => { + const customUserStatus = await getCustomUserStatus(query); + return customUserStatus; + }, }); const handleReload = (): void => { @@ -35,7 +39,7 @@ const CustomUserStatusFormWithData = ({ _id, onReload, onClose }: CustomUserStat return ; } - if (isLoading) { + if (isPending) { return ; } diff --git a/apps/meteor/client/views/admin/customUserStatus/CustomUserStatusService.tsx b/apps/meteor/client/views/admin/customUserStatus/CustomUserStatusService.tsx index aadc9434c96f..21ef3e0e94c1 100644 --- a/apps/meteor/client/views/admin/customUserStatus/CustomUserStatusService.tsx +++ b/apps/meteor/client/views/admin/customUserStatus/CustomUserStatusService.tsx @@ -24,10 +24,12 @@ const CustomUserStatusService = () => { const result = useActiveConnections(); const presenceDisabled = useSetting('Presence_broadcast_disabled', false); const togglePresenceServiceEndpoint = useEndpoint('POST', '/v1/presence.enableBroadcast'); - const disablePresenceService = useMutation(() => togglePresenceServiceEndpoint()); - const { data: license, isLoading: licenseIsLoading } = useIsEnterprise(); + const disablePresenceService = useMutation({ + mutationFn: () => togglePresenceServiceEndpoint(), + }); + const { data: license, isPending: licenseIsLoading } = useIsEnterprise(); - if (result.isLoading || disablePresenceService.isLoading || licenseIsLoading) { + if (result.isPending || disablePresenceService.isPending || licenseIsLoading) { return ( @@ -59,7 +61,7 @@ const CustomUserStatusService = () => { {t('Service_status')} disablePresenceService.mutate()} /> diff --git a/apps/meteor/client/views/admin/customUserStatus/CustomUserStatusTable/CustomUserStatusTable.tsx b/apps/meteor/client/views/admin/customUserStatus/CustomUserStatusTable/CustomUserStatusTable.tsx index ac118649e1a7..0c7b3223902c 100644 --- a/apps/meteor/client/views/admin/customUserStatus/CustomUserStatusTable/CustomUserStatusTable.tsx +++ b/apps/meteor/client/views/admin/customUserStatus/CustomUserStatusTable/CustomUserStatusTable.tsx @@ -1,7 +1,7 @@ import { Pagination } from '@rocket.chat/fuselage'; import { useDebouncedValue } from '@rocket.chat/fuselage-hooks'; import { escapeRegExp } from '@rocket.chat/string-helpers'; -import { useEndpoint, useToastMessageDispatch } from '@rocket.chat/ui-contexts'; +import { useEndpoint } from '@rocket.chat/ui-contexts'; import { useQuery } from '@tanstack/react-query'; import type { ReactElement, MutableRefObject } from 'react'; import { useState, useMemo, useEffect } from 'react'; @@ -46,20 +46,18 @@ const CustomUserStatus = ({ reload, onClick }: CustomUserStatusProps): ReactElem ); const getCustomUserStatus = useEndpoint('GET', '/v1/custom-user-status.list'); - const dispatchToastMessage = useToastMessageDispatch(); - const { data, isLoading, refetch, isFetched } = useQuery( - ['custom-user-statuses', query], - async () => { + const { data, isLoading, refetch, isFetched } = useQuery({ + queryKey: ['custom-user-statuses', query], + + queryFn: async () => { const { statuses } = await getCustomUserStatus(query); return statuses; }, - { - onError: (error) => { - dispatchToastMessage({ type: 'error', message: error }); - }, + meta: { + apiErrorToastMessage: true, }, - ); + }); useEffect(() => { reload.current = refetch; diff --git a/apps/meteor/client/views/admin/customUserStatus/hooks/useStatusDisabledModal.tsx b/apps/meteor/client/views/admin/customUserStatus/hooks/useStatusDisabledModal.tsx index 53b8338c90ff..7cb32da3cd29 100644 --- a/apps/meteor/client/views/admin/customUserStatus/hooks/useStatusDisabledModal.tsx +++ b/apps/meteor/client/views/admin/customUserStatus/hooks/useStatusDisabledModal.tsx @@ -1,4 +1,4 @@ -import { useMutableCallback } from '@rocket.chat/fuselage-hooks'; +import { useEffectEvent } from '@rocket.chat/fuselage-hooks'; import { useRole, useRoute, useSetModal } from '@rocket.chat/ui-contexts'; import CustomUserStatusDisabledModal from '../CustomUserStatusDisabledModal'; @@ -6,8 +6,8 @@ import CustomUserStatusDisabledModal from '../CustomUserStatusDisabledModal'; export const useStatusDisabledModal = () => { const userStatusRoute = useRoute('user-status'); const setModal = useSetModal(); - const closeModal = useMutableCallback(() => setModal()); - const handleGoToSettings = useMutableCallback(() => { + const closeModal = useEffectEvent(() => setModal()); + const handleGoToSettings = useEffectEvent(() => { userStatusRoute.push({ context: 'presence-service' }); closeModal(); }); diff --git a/apps/meteor/client/views/admin/deviceManagement/DeviceManagementAdminTable/DeviceManagementAdminRow.tsx b/apps/meteor/client/views/admin/deviceManagement/DeviceManagementAdminTable/DeviceManagementAdminRow.tsx index 217b8e2e5171..d591b8dd2421 100644 --- a/apps/meteor/client/views/admin/deviceManagement/DeviceManagementAdminTable/DeviceManagementAdminRow.tsx +++ b/apps/meteor/client/views/admin/deviceManagement/DeviceManagementAdminTable/DeviceManagementAdminRow.tsx @@ -1,5 +1,7 @@ -import { Box, Menu, Option } from '@rocket.chat/fuselage'; -import { useMediaQuery, useMutableCallback } from '@rocket.chat/fuselage-hooks'; +import { Box } from '@rocket.chat/fuselage'; +import { useMediaQuery, useEffectEvent } from '@rocket.chat/fuselage-hooks'; +import type { GenericMenuItemProps } from '@rocket.chat/ui-client'; +import { GenericMenu } from '@rocket.chat/ui-client'; import { useRoute } from '@rocket.chat/ui-contexts'; import type { KeyboardEvent, ReactElement } from 'react'; import { useCallback } from 'react'; @@ -40,7 +42,7 @@ const DeviceManagementAdminRow = ({ const handleDeviceLogout = useDeviceLogout(_id, '/v1/sessions/logout'); - const handleClick = useMutableCallback((): void => { + const handleClick = useEffectEvent((): void => { deviceManagementRouter.push({ context: 'info', id: _id, @@ -57,12 +59,14 @@ const DeviceManagementAdminRow = ({ [handleClick], ); - const menuOptions = { - logout: { - label: { label: t('Logout_Device'), icon: 'sign-out' }, - action: (): void => handleDeviceLogout(onReload), + const menuItems: GenericMenuItemProps[] = [ + { + id: 'logoutDevice', + icon: 'sign-out', + content: t('Logout_Device'), + onClick: (): void => handleDeviceLogout(onReload), }, - }; + ]; return ( @@ -79,11 +83,7 @@ const DeviceManagementAdminRow = ({ {mediaQuery && {_id}} {mediaQuery && {ip}} e.stopPropagation()}> -