develop ef8e3e8520b9 cached
2217 files
3.0 MB
932.2k tokens
1980 symbols
1 requests
Download .txt
Showing preview only (3,734K chars total). Download the full file or copy to clipboard to get everything.
Repository: it-incubator/musicfun-react-all-stacks
Branch: develop
Commit: ef8e3e8520b9
Files: 2217
Total size: 3.0 MB

Directory structure:
gitextract_xkduu9og/

├── .github/
│   └── workflows/
│       ├── ci-rtk.yml
│       ├── ci-tanstack.yml
│       ├── deploy-effector.yml
│       ├── deploy-reatom.yml
│       ├── deploy-root.yml
│       ├── deploy-rtk.yml
│       ├── deploy-tanstack.yml
│       └── deploy.yml
├── .gitignore
├── .husky/
│   ├── pre-commit
│   └── pre-push
├── .prettierignore
├── .prettierrc
├── CONTRIBUTING.md
├── FRONTEND_API_CHANGES.md
├── README.md
├── apps/
│   ├── nextjs/
│   │   ├── .gitignore
│   │   ├── README.md
│   │   ├── eslint.config.mjs
│   │   ├── next.config.ts
│   │   ├── package.json
│   │   ├── src/
│   │   │   ├── app/
│   │   │   │   ├── actions/
│   │   │   │   │   └── auth/
│   │   │   │   │       └── logout.action.tsx
│   │   │   │   ├── api/
│   │   │   │   │   └── oauth/
│   │   │   │   │       └── callback/
│   │   │   │   │           └── route.ts
│   │   │   │   ├── globals.css
│   │   │   │   ├── layout.tsx
│   │   │   │   ├── page.module.css
│   │   │   │   ├── page.tsx
│   │   │   │   ├── profile/
│   │   │   │   │   └── page.tsx
│   │   │   │   └── redirect/
│   │   │   │       └── page.tsx
│   │   │   ├── features/
│   │   │   │   └── auth/
│   │   │   │       └── ui/
│   │   │   │           ├── Login/
│   │   │   │           │   └── Login.tsx
│   │   │   │           ├── Logout/
│   │   │   │           │   └── Logout.tsx
│   │   │   │           ├── MeInfo/
│   │   │   │           │   └── MeInfo.tsx
│   │   │   │           └── UserBlock.tsx
│   │   │   ├── middleware.ts
│   │   │   ├── reauth-middleware.ts
│   │   │   └── shared/
│   │   │       ├── api/
│   │   │       │   ├── auth-api.ts
│   │   │       │   ├── authApi.types.ts
│   │   │       │   ├── base.ts
│   │   │       │   └── tracks/
│   │   │       │       ├── tracksApi.ts
│   │   │       │       └── tracksApi.types.ts
│   │   │       ├── common.types.ts
│   │   │       └── utils/
│   │   │           ├── cookieHelpers.ts
│   │   │           └── jwt-util.ts
│   │   └── tsconfig.json
│   ├── react-effector-fsd/
│   │   ├── .gitignore
│   │   ├── README.md
│   │   ├── eslint.config.js
│   │   ├── index.html
│   │   ├── package.json
│   │   ├── src/
│   │   │   ├── app/
│   │   │   │   ├── App.tsx
│   │   │   │   ├── main.tsx
│   │   │   │   ├── model/
│   │   │   │   │   └── init.ts
│   │   │   │   ├── routes/
│   │   │   │   │   ├── Routing.tsx
│   │   │   │   │   └── index.ts
│   │   │   │   └── styles/
│   │   │   │       ├── fonts.css
│   │   │   │       ├── global.css
│   │   │   │       ├── reset.css
│   │   │   │       └── variables.css
│   │   │   ├── features/
│   │   │   │   └── auth/
│   │   │   │       ├── api/
│   │   │   │       │   ├── login.ts
│   │   │   │       │   ├── logout.ts
│   │   │   │       │   └── me.ts
│   │   │   │       ├── index.ts
│   │   │   │       ├── model/
│   │   │   │       │   ├── auth-api.types.ts
│   │   │   │       │   ├── model.ts
│   │   │   │       │   └── user.types.ts
│   │   │   │       └── ui/
│   │   │   │           ├── LoginButtonAndModal/
│   │   │   │           │   ├── LoginButtonAndModal.module.css
│   │   │   │           │   ├── LoginButtonAndModal.tsx
│   │   │   │           │   └── index.ts
│   │   │   │           ├── ProfileDropdownMenu/
│   │   │   │           │   ├── ProfileDropdownMenu.module.css
│   │   │   │           │   ├── ProfileDropdownMenu.stories.tsx
│   │   │   │           │   ├── ProfileDropdownMenu.tsx
│   │   │   │           │   └── index.ts
│   │   │   │           └── index.ts
│   │   │   ├── pages/
│   │   │   │   ├── auth/
│   │   │   │   │   └── OAuthRedirect/
│   │   │   │   │       ├── OAuthCallback.module.css
│   │   │   │   │       └── OAuthCallback.tsx
│   │   │   │   ├── home/
│   │   │   │   │   ├── Home.tsx
│   │   │   │   │   └── index.ts
│   │   │   │   └── user/
│   │   │   │       ├── UserPage.tsx
│   │   │   │       └── index.ts
│   │   │   ├── shared/
│   │   │   │   ├── api/
│   │   │   │   │   ├── client.ts
│   │   │   │   │   ├── schema.ts
│   │   │   │   │   └── utils/
│   │   │   │   │       ├── json-api-error.ts
│   │   │   │   │       └── request-wrapper.ts
│   │   │   │   ├── components/
│   │   │   │   │   ├── AudioPlayer/
│   │   │   │   │   │   ├── AudioPlayer.module.css
│   │   │   │   │   │   ├── AudioPlayer.stories.tsx
│   │   │   │   │   │   ├── AudioPlayer.tsx
│   │   │   │   │   │   └── index.ts
│   │   │   │   │   ├── Autocomplete/
│   │   │   │   │   │   ├── Autocomplete.module.css
│   │   │   │   │   │   ├── Autocomplete.stories.tsx
│   │   │   │   │   │   ├── Autocomplete.tsx
│   │   │   │   │   │   └── index.ts
│   │   │   │   │   ├── Button/
│   │   │   │   │   │   ├── Button.module.css
│   │   │   │   │   │   ├── Button.stories.tsx
│   │   │   │   │   │   ├── Button.tsx
│   │   │   │   │   │   └── index.ts
│   │   │   │   │   ├── Card/
│   │   │   │   │   │   ├── Card.module.css
│   │   │   │   │   │   ├── Card.stories.tsx
│   │   │   │   │   │   ├── Card.tsx
│   │   │   │   │   │   └── index.ts
│   │   │   │   │   ├── Dialog/
│   │   │   │   │   │   ├── Dialog.module.css
│   │   │   │   │   │   ├── Dialog.stories.tsx
│   │   │   │   │   │   ├── Dialog.tsx
│   │   │   │   │   │   └── index.ts
│   │   │   │   │   ├── DropdownMenu/
│   │   │   │   │   │   ├── DropdownMenu.module.css
│   │   │   │   │   │   ├── DropdownMenu.stories.tsx
│   │   │   │   │   │   ├── DropdownMenu.tsx
│   │   │   │   │   │   └── index.ts
│   │   │   │   │   ├── Hashtag/
│   │   │   │   │   │   ├── Tag.module.css
│   │   │   │   │   │   ├── Tag.stories.tsx
│   │   │   │   │   │   ├── Tag.tsx
│   │   │   │   │   │   └── index.ts
│   │   │   │   │   ├── IconButton/
│   │   │   │   │   │   ├── IconButton.module.css
│   │   │   │   │   │   ├── IconButton.stories.tsx
│   │   │   │   │   │   ├── IconButton.tsx
│   │   │   │   │   │   └── index.ts
│   │   │   │   │   ├── ImageUploader/
│   │   │   │   │   │   ├── ImageUploader.module.css
│   │   │   │   │   │   ├── ImageUploader.stories.tsx
│   │   │   │   │   │   ├── ImageUploader.tsx
│   │   │   │   │   │   └── index.ts
│   │   │   │   │   ├── Pagination/
│   │   │   │   │   │   ├── Pagination.module.css
│   │   │   │   │   │   ├── Pagination.stories.tsx
│   │   │   │   │   │   ├── Pagination.tsx
│   │   │   │   │   │   └── index.ts
│   │   │   │   │   ├── Progress/
│   │   │   │   │   │   ├── Progress.module.css
│   │   │   │   │   │   ├── Progress.stories.tsx
│   │   │   │   │   │   ├── Progress.tsx
│   │   │   │   │   │   └── index.ts
│   │   │   │   │   ├── ReactionButtons/
│   │   │   │   │   │   ├── ReactionButtons.module.css
│   │   │   │   │   │   ├── ReactionButtons.stories.tsx
│   │   │   │   │   │   ├── ReactionButtons.tsx
│   │   │   │   │   │   └── index.ts
│   │   │   │   │   ├── SearchField/
│   │   │   │   │   │   ├── SearchField.module.css
│   │   │   │   │   │   ├── SearchField.stories.tsx
│   │   │   │   │   │   ├── SearchField.tsx
│   │   │   │   │   │   └── index.ts
│   │   │   │   │   ├── Select/
│   │   │   │   │   │   ├── Select.module.css
│   │   │   │   │   │   ├── Select.stories.tsx
│   │   │   │   │   │   ├── Select.tsx
│   │   │   │   │   │   └── index.ts
│   │   │   │   │   ├── SortSelect/
│   │   │   │   │   │   └── Select.tsx
│   │   │   │   │   ├── Table/
│   │   │   │   │   │   ├── Table.module.css
│   │   │   │   │   │   ├── Table.stories.tsx
│   │   │   │   │   │   ├── Table.tsx
│   │   │   │   │   │   └── index.ts
│   │   │   │   │   ├── Tabs/
│   │   │   │   │   │   ├── Tabs.module.css
│   │   │   │   │   │   ├── Tabs.stories.tsx
│   │   │   │   │   │   ├── Tabs.tsx
│   │   │   │   │   │   └── index.ts
│   │   │   │   │   ├── TagEditor/
│   │   │   │   │   │   ├── TagEditor.module.css
│   │   │   │   │   │   ├── TagEditor.stories.tsx
│   │   │   │   │   │   ├── TagEditor.tsx
│   │   │   │   │   │   └── index.ts
│   │   │   │   │   ├── TextField/
│   │   │   │   │   │   ├── TextField.module.css
│   │   │   │   │   │   ├── TextField.stories.tsx
│   │   │   │   │   │   ├── TextField.tsx
│   │   │   │   │   │   └── index.ts
│   │   │   │   │   ├── Textarea/
│   │   │   │   │   │   ├── Textarea.module.css
│   │   │   │   │   │   ├── Textarea.stories.tsx
│   │   │   │   │   │   ├── Textarea.tsx
│   │   │   │   │   │   └── index.ts
│   │   │   │   │   ├── Typography/
│   │   │   │   │   │   ├── Typography.module.css
│   │   │   │   │   │   ├── Typography.stories.tsx
│   │   │   │   │   │   ├── Typography.tsx
│   │   │   │   │   │   └── index.ts
│   │   │   │   │   └── index.ts
│   │   │   │   ├── config/
│   │   │   │   │   └── config.ts
│   │   │   │   ├── hooks/
│   │   │   │   │   ├── index.ts
│   │   │   │   │   ├── useDebounceValue.ts
│   │   │   │   │   └── useGetId.ts
│   │   │   │   └── icons/
│   │   │   │       ├── AddToPlaylistIcon.tsx
│   │   │   │       ├── ArrowDownIcon.tsx
│   │   │   │       ├── ClockIcon.tsx
│   │   │   │       ├── CreateIcon.tsx
│   │   │   │       ├── DeleteIcon.tsx
│   │   │   │       ├── DislikeIcon.tsx
│   │   │   │       ├── DownloadIcon.tsx
│   │   │   │       ├── EditIcon.tsx
│   │   │   │       ├── HomeIcon.tsx
│   │   │   │       ├── ImageUploadIcon.tsx
│   │   │   │       ├── KeyboardArrowLeftIcon.tsx
│   │   │   │       ├── KeyboardArrowRightIcon.tsx
│   │   │   │       ├── LibraryIcon.tsx
│   │   │   │       ├── LikeIcon.tsx
│   │   │   │       ├── LikeIconFill.tsx
│   │   │   │       ├── LikeInSquareIcon.tsx
│   │   │   │       ├── LiveWaveIcon/
│   │   │   │       │   ├── LiveWaveIcon.module.css
│   │   │   │       │   ├── LiveWaveIcon.tsx
│   │   │   │       │   └── index.ts
│   │   │   │       ├── LogoutIcon.tsx
│   │   │   │       ├── MoreIcon.tsx
│   │   │   │       ├── PauseIcon.tsx
│   │   │   │       ├── PlayIcon.tsx
│   │   │   │       ├── PlaylistIcon.tsx
│   │   │   │       ├── PlusIcon.tsx
│   │   │   │       ├── ProfileIcon.tsx
│   │   │   │       ├── RepeatIcon.tsx
│   │   │   │       ├── SearchIcon.tsx
│   │   │   │       ├── ShuffleIcon.tsx
│   │   │   │       ├── SkipNextIcon.tsx
│   │   │   │       ├── SkipPreviousIcon.tsx
│   │   │   │       ├── TextIcon.tsx
│   │   │   │       ├── TrackIcon.tsx
│   │   │   │       ├── UploadIcon.tsx
│   │   │   │       ├── VolumeIcon.tsx
│   │   │   │       ├── VolumeMuteIcon.tsx
│   │   │   │       └── index.ts
│   │   │   └── widgets/
│   │   │       └── layout/
│   │   │           ├── index.ts
│   │   │           └── ui/
│   │   │               ├── Header/
│   │   │               │   ├── Header.module.css
│   │   │               │   └── Header.tsx
│   │   │               ├── Layout.module.css
│   │   │               ├── Layout.tsx
│   │   │               └── Sidebar/
│   │   │                   ├── MenuLinks/
│   │   │                   │   ├── MenuLinks.module.css
│   │   │                   │   └── MenuLinks.tsx
│   │   │                   ├── Sidebar.module.css
│   │   │                   └── Sidebar.tsx
│   │   ├── tsconfig.json
│   │   └── vite.config.ts
│   ├── react-native-expo/
│   │   ├── .gitignore
│   │   ├── .npmrc
│   │   ├── app/
│   │   │   ├── (app)/
│   │   │   │   ├── _layout.tsx
│   │   │   │   ├── index.tsx
│   │   │   │   ├── library/
│   │   │   │   │   └── library.tsx
│   │   │   │   ├── playlists/
│   │   │   │   │   └── playlists.tsx
│   │   │   │   └── tracks/
│   │   │   │       └── tracks.tsx
│   │   │   ├── (auth)/
│   │   │   │   ├── _layout.tsx
│   │   │   │   └── login.tsx
│   │   │   └── _layout.tsx
│   │   ├── app.config.ts
│   │   ├── babel.config.js
│   │   ├── declarations.d.ts
│   │   ├── features/
│   │   │   ├── auth/
│   │   │   │   ├── components/
│   │   │   │   │   ├── LoginButton/
│   │   │   │   │   │   └── LoginButton.tsx
│   │   │   │   │   └── LogoutButton/
│   │   │   │   │       └── LogoutButton.tsx
│   │   │   │   └── model/
│   │   │   │       ├── api/
│   │   │   │       │   ├── auth-instanse/
│   │   │   │       │   │   └── auth-instanse.ts
│   │   │   │       │   └── hooks/
│   │   │   │       │       ├── use-login-mutatuion.ts
│   │   │   │       │       ├── use-logout-mutation.ts
│   │   │   │       │       └── use-me.query.ts
│   │   │   │       ├── config/
│   │   │   │       │   └── oauth.ts
│   │   │   │       ├── context/
│   │   │   │       │   └── AuthContext.tsx
│   │   │   │       ├── types/
│   │   │   │       │   └── api.types.ts
│   │   │   │       └── utils/
│   │   │   │           ├── expoUrlToHttpCallback.ts
│   │   │   │           └── getOauthRedirectUrl.ts
│   │   │   └── playlists/
│   │   │       └── model/
│   │   │           └── api/
│   │   │               └── playlist-instance/
│   │   │                   └── playlist-instance.ts
│   │   ├── index.ts
│   │   ├── metro.config.js
│   │   ├── package.json
│   │   ├── pnpm-lock.yaml.2457664388
│   │   ├── shared/
│   │   │   ├── api/
│   │   │   │   ├── api-root/
│   │   │   │   │   ├── api-root-instanse.ts
│   │   │   │   │   └── api-root.ts
│   │   │   │   ├── query-client/
│   │   │   │   │   └── queryClient.ts
│   │   │   │   └── query-persist/
│   │   │   │       └── query-presist.ts
│   │   │   ├── consts/
│   │   │   │   ├── consts.ts
│   │   │   │   └── key-storage/
│   │   │   │       └── key-storage.ts
│   │   │   ├── providers/
│   │   │   │   └── reactQueryProviders/
│   │   │   │       └── ReactQueryProviders.tsx
│   │   │   ├── storage/
│   │   │   │   └── tokenStorage.ts
│   │   │   ├── styles/
│   │   │   │   ├── tokens.ts
│   │   │   │   └── tokens.type.ts
│   │   │   ├── ui/
│   │   │   │   ├── Button/
│   │   │   │   │   ├── Button.tsx
│   │   │   │   │   └── Button.type.tsx
│   │   │   │   └── Icons/
│   │   │   │       ├── navigation/
│   │   │   │       │   ├── IcAllPlaylist.tsx
│   │   │   │       │   ├── IcAllTracks.tsx
│   │   │   │       │   ├── IcHome.tsx
│   │   │   │       │   └── IcYourLibrary.tsx
│   │   │   │       └── screens/
│   │   │   │           └── login/
│   │   │   │               └── IcSmile.tsx
│   │   │   └── utils/
│   │   │       └── makeFullUrl.ts
│   │   └── tsconfig.json
│   ├── reatom/
│   │   ├── .gitignore
│   │   ├── .storybook/
│   │   │   ├── main.ts
│   │   │   └── preview.tsx
│   │   ├── README.md
│   │   ├── eslint.config.js
│   │   ├── index.html
│   │   ├── package.json
│   │   ├── src/
│   │   │   ├── app/
│   │   │   │   ├── App.tsx
│   │   │   │   ├── entrypoint/
│   │   │   │   │   └── main.tsx
│   │   │   │   ├── query-client/
│   │   │   │   │   └── query-client.tsx
│   │   │   │   ├── routing/
│   │   │   │   │   ├── Routing.tsx
│   │   │   │   │   └── index.ts
│   │   │   │   └── styles/
│   │   │   │       ├── fonts.css
│   │   │   │       ├── global.css
│   │   │   │       ├── reset.css
│   │   │   │       └── variables.css
│   │   │   ├── entities/
│   │   │   │   └── playlist/
│   │   │   │       ├── index.tsx
│   │   │   │       └── ui/
│   │   │   │           ├── PlaylistCard/
│   │   │   │           │   ├── PlaylistCard.module.css
│   │   │   │           │   ├── PlaylistCard.stories.tsx
│   │   │   │           │   ├── PlaylistCard.tsx
│   │   │   │           │   └── index.ts
│   │   │   │           └── PlaylistItem/
│   │   │   │               ├── PlaylistItem.tsx
│   │   │   │               ├── PlaylistItem.types.ts
│   │   │   │               └── index.ts
│   │   │   ├── features/
│   │   │   │   ├── artists/
│   │   │   │   │   ├── api/
│   │   │   │   │   │   ├── artists-api.ts
│   │   │   │   │   │   └── index.ts
│   │   │   │   │   ├── index.ts
│   │   │   │   │   └── ui/
│   │   │   │   │       └── ArtistCard/
│   │   │   │   │           ├── ArtistCard.module.css
│   │   │   │   │           ├── ArtistCard.stories.tsx
│   │   │   │   │           ├── ArtistCard.tsx
│   │   │   │   │           └── index.ts
│   │   │   │   ├── auth/
│   │   │   │   │   ├── api/
│   │   │   │   │   │   ├── use-login.mutation.ts
│   │   │   │   │   │   ├── use-logout.mutation.ts
│   │   │   │   │   │   └── use-me.query.ts
│   │   │   │   │   ├── index.ts
│   │   │   │   │   ├── types/
│   │   │   │   │   │   └── auth-api.types.ts
│   │   │   │   │   └── ui/
│   │   │   │   │       ├── LoginButtonAndModal/
│   │   │   │   │       │   ├── LoginButtonAndModal.module.css
│   │   │   │   │       │   ├── LoginButtonAndModal.tsx
│   │   │   │   │       │   └── index.ts
│   │   │   │   │       ├── ProfileDropdownMenu/
│   │   │   │   │       │   ├── ProfileDropdownMenu.module.css
│   │   │   │   │       │   ├── ProfileDropdownMenu.stories.tsx
│   │   │   │   │       │   ├── ProfileDropdownMenu.tsx
│   │   │   │   │       │   └── index.ts
│   │   │   │   │       └── index.ts
│   │   │   │   ├── playlists/
│   │   │   │   │   ├── api/
│   │   │   │   │   │   ├── index.ts
│   │   │   │   │   │   ├── playlistsApi.ts
│   │   │   │   │   │   ├── query-key-factory.ts
│   │   │   │   │   │   ├── types.ts
│   │   │   │   │   │   └── use-playlists.query.ts
│   │   │   │   │   ├── index.ts
│   │   │   │   │   ├── model/
│   │   │   │   │   │   └── model.tsx
│   │   │   │   │   └── ui/
│   │   │   │   │       ├── CreatePlaylistModal/
│   │   │   │   │       │   ├── CreatePlaylistModal.module.css
│   │   │   │   │       │   ├── CreatePlaylistModal.tsx
│   │   │   │   │       │   └── index.ts
│   │   │   │   │       ├── PlaylistOverview/
│   │   │   │   │       │   ├── PlaylistOverview.module.css
│   │   │   │   │       │   ├── PlaylistOverview.stories.tsx
│   │   │   │   │       │   ├── PlaylistOverview.tsx
│   │   │   │   │       │   └── index.ts
│   │   │   │   │       └── index.ts
│   │   │   │   ├── reactions/
│   │   │   │   │   ├── index.ts
│   │   │   │   │   └── ui/
│   │   │   │   │       ├── ReactionProvider/
│   │   │   │   │       │   ├── ReactionProvider.tsx
│   │   │   │   │       │   └── index.ts
│   │   │   │   │       └── index.ts
│   │   │   │   ├── tags/
│   │   │   │   │   ├── api/
│   │   │   │   │   │   ├── index.ts
│   │   │   │   │   │   ├── tags-api.ts
│   │   │   │   │   │   └── use-tags.query.ts
│   │   │   │   │   ├── index.ts
│   │   │   │   │   └── ui/
│   │   │   │   │       ├── TagsList/
│   │   │   │   │       │   ├── TagsList.module.css
│   │   │   │   │       │   ├── TagsList.stories.tsx
│   │   │   │   │       │   ├── TagsList.tsx
│   │   │   │   │       │   └── index.ts
│   │   │   │   │       └── index.ts
│   │   │   │   └── tracks/
│   │   │   │       ├── api/
│   │   │   │       │   ├── index.ts
│   │   │   │       │   ├── tracksApi.ts
│   │   │   │       │   └── types.ts
│   │   │   │       ├── index.ts
│   │   │   │       └── ui/
│   │   │   │           ├── TrackCard/
│   │   │   │           │   ├── TrackCard.module.css
│   │   │   │           │   ├── TrackCard.stories.tsx
│   │   │   │           │   ├── TrackCard.tsx
│   │   │   │           │   └── index.ts
│   │   │   │           ├── TrackInfoCell/
│   │   │   │           │   ├── TrackInfoCell.module.css
│   │   │   │           │   ├── TrackInfoCell.tsx
│   │   │   │           │   └── index.ts
│   │   │   │           ├── TrackOverview/
│   │   │   │           │   ├── TrackOverview.module.css
│   │   │   │           │   ├── TrackOverview.stories.tsx
│   │   │   │           │   ├── TrackOverview.tsx
│   │   │   │           │   └── index.ts
│   │   │   │           ├── TrackRow/
│   │   │   │           │   ├── TrackRow.module.css
│   │   │   │           │   └── TrackRow.tsx
│   │   │   │           ├── TracksTable/
│   │   │   │           │   ├── TrackTable.stories.tsx
│   │   │   │           │   ├── TracksTable.tsx
│   │   │   │           │   └── index.ts
│   │   │   │           └── index.ts
│   │   │   ├── layout/
│   │   │   │   ├── Header/
│   │   │   │   │   ├── Header.module.css
│   │   │   │   │   ├── Header.tsx
│   │   │   │   │   └── index.ts
│   │   │   │   ├── Layout.module.css
│   │   │   │   ├── Layout.tsx
│   │   │   │   ├── Sidebar/
│   │   │   │   │   ├── MenuLinks/
│   │   │   │   │   │   ├── MenuLinks.module.css
│   │   │   │   │   │   ├── MenuLinks.tsx
│   │   │   │   │   │   └── index.ts
│   │   │   │   │   ├── Sidebar.module.css
│   │   │   │   │   ├── Sidebar.tsx
│   │   │   │   │   └── index.ts
│   │   │   │   └── index.ts
│   │   │   ├── pages/
│   │   │   │   ├── MainPage/
│   │   │   │   │   ├── MainPage.module.css
│   │   │   │   │   ├── MainPage.tsx
│   │   │   │   │   └── index.ts
│   │   │   │   ├── PlaylistPage/
│   │   │   │   │   ├── PlaylistPage.module.css
│   │   │   │   │   ├── PlaylistPage.tsx
│   │   │   │   │   ├── index.ts
│   │   │   │   │   └── ui/
│   │   │   │   │       └── ControlPanel/
│   │   │   │   │           ├── ControlPanel.module.css
│   │   │   │   │           ├── ControlPanel.tsx
│   │   │   │   │           └── index.ts
│   │   │   │   ├── PlaylistsPage/
│   │   │   │   │   ├── PlaylistsPage.module.css
│   │   │   │   │   ├── PlaylistsPage.tsx
│   │   │   │   │   ├── PlaylistsPage.types.ts
│   │   │   │   │   └── index.ts
│   │   │   │   ├── TrackPage/
│   │   │   │   │   ├── TrackPage.module.css
│   │   │   │   │   ├── TrackPage.tsx
│   │   │   │   │   ├── index.ts
│   │   │   │   │   └── ui/
│   │   │   │   │       └── ControlPanel/
│   │   │   │   │           ├── ControlPanel.module.css
│   │   │   │   │           ├── ControlPanel.tsx
│   │   │   │   │           └── index.ts
│   │   │   │   ├── TracksPage/
│   │   │   │   │   ├── TracksPage.module.css
│   │   │   │   │   ├── TracksPage.tsx
│   │   │   │   │   └── index.ts
│   │   │   │   ├── UserPage/
│   │   │   │   │   ├── UserPage.module.css
│   │   │   │   │   ├── UserPage.tsx
│   │   │   │   │   ├── index.ts
│   │   │   │   │   └── ui/
│   │   │   │   │       ├── UserInfo/
│   │   │   │   │       │   ├── UserInfo.module.css
│   │   │   │   │       │   ├── UserInfo.tsx
│   │   │   │   │       │   └── index.ts
│   │   │   │   │       ├── UserTabs/
│   │   │   │   │       │   ├── LikedTracksTab/
│   │   │   │   │       │   │   ├── LikedTracksTab.module.css
│   │   │   │   │       │   │   ├── LikedTracksTab.tsx
│   │   │   │   │       │   │   └── index.ts
│   │   │   │   │       │   ├── MyLikedPlaylistsTab/
│   │   │   │   │       │   │   ├── MyLikedPlaylistsTab.tsx
│   │   │   │   │       │   │   └── index.ts
│   │   │   │   │       │   ├── PlaylistsTab/
│   │   │   │   │       │   │   ├── PlaylistsTab.module.css
│   │   │   │   │       │   │   ├── PlaylistsTab.tsx
│   │   │   │   │       │   │   └── index.ts
│   │   │   │   │       │   ├── TracksTab/
│   │   │   │   │       │   │   ├── TracksTab.module.css
│   │   │   │   │       │   │   ├── TracksTab.tsx
│   │   │   │   │       │   │   └── index.ts
│   │   │   │   │       │   ├── UserTabs.tsx
│   │   │   │   │       │   └── index.ts
│   │   │   │   │       └── index.ts
│   │   │   │   ├── auth/
│   │   │   │   │   └── OAuthRedirect/
│   │   │   │   │       ├── OAuthCallback.module.css
│   │   │   │   │       └── OAuthCallback.tsx
│   │   │   │   ├── common/
│   │   │   │   │   ├── ContentList/
│   │   │   │   │   │   ├── ContentList.module.css
│   │   │   │   │   │   ├── ContentList.tsx
│   │   │   │   │   │   └── index.ts
│   │   │   │   │   ├── PageWrapper/
│   │   │   │   │   │   ├── PageWrapper.module.css
│   │   │   │   │   │   ├── PageWrapper.tsx
│   │   │   │   │   │   └── index.ts
│   │   │   │   │   ├── SearchTextField/
│   │   │   │   │   │   ├── SearchTextField.tsx
│   │   │   │   │   │   └── index.ts
│   │   │   │   │   ├── SortSelect/
│   │   │   │   │   │   ├── SortSelect.module.css
│   │   │   │   │   │   ├── SortSelect.tsx
│   │   │   │   │   │   └── index.ts
│   │   │   │   │   └── index.ts
│   │   │   │   └── index.ts
│   │   │   ├── shared/
│   │   │   │   ├── api/
│   │   │   │   │   ├── client.ts
│   │   │   │   │   ├── schema.ts
│   │   │   │   │   ├── types.ts
│   │   │   │   │   └── utils/
│   │   │   │   │       ├── json-api-error.ts
│   │   │   │   │       └── request-wrapper.ts
│   │   │   │   ├── components/
│   │   │   │   │   ├── AudioPlayer/
│   │   │   │   │   │   ├── AudioPlayer.module.css
│   │   │   │   │   │   ├── AudioPlayer.stories.tsx
│   │   │   │   │   │   ├── AudioPlayer.tsx
│   │   │   │   │   │   └── index.ts
│   │   │   │   │   ├── Autocomplete/
│   │   │   │   │   │   ├── Autocomplete.module.css
│   │   │   │   │   │   ├── Autocomplete.stories.tsx
│   │   │   │   │   │   ├── Autocomplete.tsx
│   │   │   │   │   │   └── index.ts
│   │   │   │   │   ├── Button/
│   │   │   │   │   │   ├── Button.module.css
│   │   │   │   │   │   ├── Button.stories.tsx
│   │   │   │   │   │   ├── Button.tsx
│   │   │   │   │   │   └── index.ts
│   │   │   │   │   ├── Card/
│   │   │   │   │   │   ├── Card.module.css
│   │   │   │   │   │   ├── Card.stories.tsx
│   │   │   │   │   │   ├── Card.tsx
│   │   │   │   │   │   └── index.ts
│   │   │   │   │   ├── Dialog/
│   │   │   │   │   │   ├── Dialog.module.css
│   │   │   │   │   │   ├── Dialog.stories.tsx
│   │   │   │   │   │   ├── Dialog.tsx
│   │   │   │   │   │   └── index.ts
│   │   │   │   │   ├── DropdownMenu/
│   │   │   │   │   │   ├── DropdownMenu.module.css
│   │   │   │   │   │   ├── DropdownMenu.stories.tsx
│   │   │   │   │   │   ├── DropdownMenu.tsx
│   │   │   │   │   │   └── index.ts
│   │   │   │   │   ├── Hashtag/
│   │   │   │   │   │   ├── Tag.module.css
│   │   │   │   │   │   ├── Tag.stories.tsx
│   │   │   │   │   │   ├── Tag.tsx
│   │   │   │   │   │   └── index.ts
│   │   │   │   │   ├── IconButton/
│   │   │   │   │   │   ├── IconButton.module.css
│   │   │   │   │   │   ├── IconButton.stories.tsx
│   │   │   │   │   │   ├── IconButton.tsx
│   │   │   │   │   │   └── index.ts
│   │   │   │   │   ├── ImageUploader/
│   │   │   │   │   │   ├── ImageUploader.module.css
│   │   │   │   │   │   ├── ImageUploader.stories.tsx
│   │   │   │   │   │   ├── ImageUploader.tsx
│   │   │   │   │   │   └── index.ts
│   │   │   │   │   ├── Pagination/
│   │   │   │   │   │   ├── Pagination.module.css
│   │   │   │   │   │   ├── Pagination.stories.tsx
│   │   │   │   │   │   ├── Pagination.tsx
│   │   │   │   │   │   └── index.ts
│   │   │   │   │   ├── Progress/
│   │   │   │   │   │   ├── Progress.module.css
│   │   │   │   │   │   ├── Progress.stories.tsx
│   │   │   │   │   │   ├── Progress.tsx
│   │   │   │   │   │   └── index.ts
│   │   │   │   │   ├── ReactionButtons/
│   │   │   │   │   │   ├── ReactionButtons.module.css
│   │   │   │   │   │   ├── ReactionButtons.stories.tsx
│   │   │   │   │   │   ├── ReactionButtons.tsx
│   │   │   │   │   │   └── index.ts
│   │   │   │   │   ├── SearchField/
│   │   │   │   │   │   ├── SearchField.module.css
│   │   │   │   │   │   ├── SearchField.stories.tsx
│   │   │   │   │   │   ├── SearchField.tsx
│   │   │   │   │   │   └── index.ts
│   │   │   │   │   ├── Select/
│   │   │   │   │   │   ├── Select.module.css
│   │   │   │   │   │   ├── Select.stories.tsx
│   │   │   │   │   │   ├── Select.tsx
│   │   │   │   │   │   └── index.ts
│   │   │   │   │   ├── SortSelect/
│   │   │   │   │   │   └── Select.tsx
│   │   │   │   │   ├── Table/
│   │   │   │   │   │   ├── Table.module.css
│   │   │   │   │   │   ├── Table.stories.tsx
│   │   │   │   │   │   ├── Table.tsx
│   │   │   │   │   │   └── index.ts
│   │   │   │   │   ├── Tabs/
│   │   │   │   │   │   ├── Tabs.module.css
│   │   │   │   │   │   ├── Tabs.stories.tsx
│   │   │   │   │   │   ├── Tabs.tsx
│   │   │   │   │   │   └── index.ts
│   │   │   │   │   ├── TagEditor/
│   │   │   │   │   │   ├── TagEditor.module.css
│   │   │   │   │   │   ├── TagEditor.stories.tsx
│   │   │   │   │   │   ├── TagEditor.tsx
│   │   │   │   │   │   └── index.ts
│   │   │   │   │   ├── TextField/
│   │   │   │   │   │   ├── TextField.module.css
│   │   │   │   │   │   ├── TextField.stories.tsx
│   │   │   │   │   │   ├── TextField.tsx
│   │   │   │   │   │   └── index.ts
│   │   │   │   │   ├── Textarea/
│   │   │   │   │   │   ├── Textarea.module.css
│   │   │   │   │   │   ├── Textarea.stories.tsx
│   │   │   │   │   │   ├── Textarea.tsx
│   │   │   │   │   │   └── index.ts
│   │   │   │   │   ├── Typography/
│   │   │   │   │   │   ├── Typography.module.css
│   │   │   │   │   │   ├── Typography.stories.tsx
│   │   │   │   │   │   ├── Typography.tsx
│   │   │   │   │   │   └── index.ts
│   │   │   │   │   └── index.ts
│   │   │   │   ├── config/
│   │   │   │   │   └── config.ts
│   │   │   │   ├── hooks/
│   │   │   │   │   ├── index.ts
│   │   │   │   │   ├── useDebounceValue.ts
│   │   │   │   │   └── useGetId.ts
│   │   │   │   ├── icons/
│   │   │   │   │   ├── AddToPlaylistIcon.tsx
│   │   │   │   │   ├── ArrowDownIcon.tsx
│   │   │   │   │   ├── ClockIcon.tsx
│   │   │   │   │   ├── CreateIcon.tsx
│   │   │   │   │   ├── DeleteIcon.tsx
│   │   │   │   │   ├── DislikeIcon.tsx
│   │   │   │   │   ├── DownloadIcon.tsx
│   │   │   │   │   ├── EditIcon.tsx
│   │   │   │   │   ├── HomeIcon.tsx
│   │   │   │   │   ├── ImageUploadIcon.tsx
│   │   │   │   │   ├── KeyboardArrowLeftIcon.tsx
│   │   │   │   │   ├── KeyboardArrowRightIcon.tsx
│   │   │   │   │   ├── LibraryIcon.tsx
│   │   │   │   │   ├── LikeIcon.tsx
│   │   │   │   │   ├── LikeIconFill.tsx
│   │   │   │   │   ├── LikeInSquareIcon.tsx
│   │   │   │   │   ├── LiveWaveIcon/
│   │   │   │   │   │   ├── LiveWaveIcon.module.css
│   │   │   │   │   │   ├── LiveWaveIcon.tsx
│   │   │   │   │   │   └── index.ts
│   │   │   │   │   ├── LogoutIcon.tsx
│   │   │   │   │   ├── MoreIcon.tsx
│   │   │   │   │   ├── PauseIcon.tsx
│   │   │   │   │   ├── PlayIcon.tsx
│   │   │   │   │   ├── PlaylistIcon.tsx
│   │   │   │   │   ├── PlusIcon.tsx
│   │   │   │   │   ├── ProfileIcon.tsx
│   │   │   │   │   ├── RepeatIcon.tsx
│   │   │   │   │   ├── SearchIcon.tsx
│   │   │   │   │   ├── ShuffleIcon.tsx
│   │   │   │   │   ├── SkipNextIcon.tsx
│   │   │   │   │   ├── SkipPreviousIcon.tsx
│   │   │   │   │   ├── TextIcon.tsx
│   │   │   │   │   ├── TrackIcon.tsx
│   │   │   │   │   ├── UploadIcon.tsx
│   │   │   │   │   ├── VolumeIcon.tsx
│   │   │   │   │   ├── VolumeMuteIcon.tsx
│   │   │   │   │   └── index.ts
│   │   │   │   ├── ui/
│   │   │   │   │   ├── prerender-ready.tsx
│   │   │   │   │   └── utils/
│   │   │   │   │       └── query-error-handler-for-rhf-factory.ts
│   │   │   │   └── utils/
│   │   │   │       ├── index.ts
│   │   │   │       └── validators/
│   │   │   │           ├── getType.ts
│   │   │   │           ├── inNun.ts
│   │   │   │           ├── index.ts
│   │   │   │           ├── isArray.ts
│   │   │   │           ├── isFunction.ts
│   │   │   │           ├── isNull.ts
│   │   │   │           ├── isObject.ts
│   │   │   │           ├── isUndefined.ts
│   │   │   │           ├── isValid.ts
│   │   │   │           └── isValidArray.ts
│   │   │   ├── vite-env.d.ts
│   │   │   └── widgets/
│   │   │       └── Player/
│   │   │           ├── Player.module.css
│   │   │           ├── Player.tsx
│   │   │           └── index.ts
│   │   ├── stylelint.config.js
│   │   ├── tsconfig.app.json
│   │   ├── tsconfig.json
│   │   ├── tsconfig.node.json
│   │   └── vite.config.ts
│   ├── rtk-query/
│   │   ├── .gitignore
│   │   ├── .storybook/
│   │   │   ├── main.ts
│   │   │   └── preview.tsx
│   │   ├── CLAUDE.md
│   │   ├── README.md
│   │   ├── eslint.config.js
│   │   ├── index.html
│   │   ├── package.json
│   │   ├── src/
│   │   │   ├── app/
│   │   │   │   ├── App.tsx
│   │   │   │   ├── api/
│   │   │   │   │   ├── base-api.ts
│   │   │   │   │   ├── base-query-with-refresh-token-flow-api.ts
│   │   │   │   │   ├── handleError.ts
│   │   │   │   │   └── index.ts
│   │   │   │   ├── routing/
│   │   │   │   │   ├── Routing.tsx
│   │   │   │   │   └── index.ts
│   │   │   │   └── store/
│   │   │   │       ├── index.ts
│   │   │   │       └── store.ts
│   │   │   ├── features/
│   │   │   │   ├── artists/
│   │   │   │   │   ├── api/
│   │   │   │   │   │   ├── artists-api.ts
│   │   │   │   │   │   └── index.ts
│   │   │   │   │   ├── index.ts
│   │   │   │   │   └── ui/
│   │   │   │   │       ├── ArtistCard/
│   │   │   │   │       │   ├── ArtistCard.module.css
│   │   │   │   │       │   ├── ArtistCard.stories.tsx
│   │   │   │   │       │   ├── ArtistCard.tsx
│   │   │   │   │       │   └── index.ts
│   │   │   │   │       ├── ArtistsTagAutocomplete/
│   │   │   │   │       │   ├── ArtistsTagAutocomplete.module.css
│   │   │   │   │       │   ├── ArtistsTagAutocomplete.tsx
│   │   │   │   │       │   └── index.ts
│   │   │   │   │       └── index.ts
│   │   │   │   ├── auth/
│   │   │   │   │   ├── api/
│   │   │   │   │   │   ├── auth-api.ts
│   │   │   │   │   │   ├── auth-api.types.ts
│   │   │   │   │   │   └── index.ts
│   │   │   │   │   ├── index.ts
│   │   │   │   │   ├── model/
│   │   │   │   │   │   ├── auth-slice.ts
│   │   │   │   │   │   └── index.ts
│   │   │   │   │   └── ui/
│   │   │   │   │       ├── LoginModal/
│   │   │   │   │       │   ├── LoginModal.module.css
│   │   │   │   │       │   ├── LoginModal.tsx
│   │   │   │   │       │   └── index.ts
│   │   │   │   │       ├── OAuthRedirect/
│   │   │   │   │       │   ├── OAuthCallback.module.css
│   │   │   │   │       │   ├── OAuthCallback.tsx
│   │   │   │   │       │   └── index.ts
│   │   │   │   │       └── index.ts
│   │   │   │   ├── playlists/
│   │   │   │   │   ├── api/
│   │   │   │   │   │   ├── index.ts
│   │   │   │   │   │   ├── mocks.ts
│   │   │   │   │   │   ├── playlistsApi.ts
│   │   │   │   │   │   └── playlistsApi.types.ts
│   │   │   │   │   ├── index.ts
│   │   │   │   │   ├── model/
│   │   │   │   │   │   ├── hooks/
│   │   │   │   │   │   │   ├── index.ts
│   │   │   │   │   │   │   ├── useCreatePlaylistModal.ts
│   │   │   │   │   │   │   └── useEditPlaylistModal.ts
│   │   │   │   │   │   ├── index.ts
│   │   │   │   │   │   └── playlists-slice.ts
│   │   │   │   │   └── ui/
│   │   │   │   │       ├── ChoosePlaylistButtonAndModal/
│   │   │   │   │       │   ├── ChoosePlaylistButtonAndModal.module.css
│   │   │   │   │       │   ├── ChoosePlaylistButtonAndModal.tsx
│   │   │   │   │       │   └── index.ts
│   │   │   │   │       ├── ChoosePlaylistModal/
│   │   │   │   │       │   ├── ChoosePlaylistModal.module.css
│   │   │   │   │       │   ├── ChoosePlaylistModal.tsx
│   │   │   │   │       │   └── index.ts
│   │   │   │   │       ├── CreateEditPlaylistModal/
│   │   │   │   │       │   ├── CreateEditPlaylistModal.module.css
│   │   │   │   │       │   ├── CreateEditPlaylistModal.tsx
│   │   │   │   │       │   └── index.ts
│   │   │   │   │       ├── PlaylistActions/
│   │   │   │   │       │   ├── PlaylistActions.tsx
│   │   │   │   │       │   └── index.ts
│   │   │   │   │       ├── PlaylistCard/
│   │   │   │   │       │   ├── PlaylistCard.module.css
│   │   │   │   │       │   ├── PlaylistCard.stories.tsx
│   │   │   │   │       │   ├── PlaylistCard.tsx
│   │   │   │   │       │   └── index.ts
│   │   │   │   │       ├── PlaylistCardSkeleton/
│   │   │   │   │       │   ├── PlaylistCardSkeleton.stories.tsx
│   │   │   │   │       │   ├── PlaylistCardSkeleton.tsx
│   │   │   │   │       │   └── index.ts
│   │   │   │   │       ├── PlaylistOverview/
│   │   │   │   │       │   ├── PlaylistOverview.module.css
│   │   │   │   │       │   ├── PlaylistOverview.stories.tsx
│   │   │   │   │       │   ├── PlaylistOverview.tsx
│   │   │   │   │       │   └── index.ts
│   │   │   │   │       ├── PlaylistRow/
│   │   │   │   │       │   ├── PlaylistRow.module.css
│   │   │   │   │       │   └── PlaylistRow.tsx
│   │   │   │   │       └── index.ts
│   │   │   │   ├── profile/
│   │   │   │   │   ├── config/
│   │   │   │   │   │   ├── empty-profile.ts
│   │   │   │   │   │   └── index.ts
│   │   │   │   │   ├── index.ts
│   │   │   │   │   ├── model/
│   │   │   │   │   │   ├── hook/
│   │   │   │   │   │   │   ├── index.ts
│   │   │   │   │   │   │   ├── useEditProfileModal.ts
│   │   │   │   │   │   │   └── useEditProfileSchema.ts
│   │   │   │   │   │   ├── index.ts
│   │   │   │   │   │   ├── profile-schemas.ts
│   │   │   │   │   │   └── profile-slice.ts
│   │   │   │   │   ├── types/
│   │   │   │   │   │   ├── index.ts
│   │   │   │   │   │   └── profile.type.ts
│   │   │   │   │   ├── ui/
│   │   │   │   │   │   ├── EditProfileModal/
│   │   │   │   │   │   │   ├── EditProfileModal.module.css
│   │   │   │   │   │   │   ├── EditProfileModal.tsx
│   │   │   │   │   │   │   └── index.ts
│   │   │   │   │   │   └── index.ts
│   │   │   │   │   └── utils/
│   │   │   │   │       ├── index.ts
│   │   │   │   │       └── storage-key.ts
│   │   │   │   ├── tags/
│   │   │   │   │   ├── api/
│   │   │   │   │   │   ├── index.ts
│   │   │   │   │   │   ├── tagsApi.ts
│   │   │   │   │   │   └── tagsApi.types.ts
│   │   │   │   │   ├── index.ts
│   │   │   │   │   └── ui/
│   │   │   │   │       ├── PlaylistTagAutocomplete/
│   │   │   │   │       │   ├── PlaylistTagAutocomplete.module.css
│   │   │   │   │       │   ├── PlaylistTagAutocomplete.tsx
│   │   │   │   │       │   └── index.ts
│   │   │   │   │       ├── TagsList/
│   │   │   │   │       │   ├── TagsList.module.css
│   │   │   │   │       │   ├── TagsList.stories.tsx
│   │   │   │   │       │   ├── TagsList.tsx
│   │   │   │   │       │   └── index.ts
│   │   │   │   │       └── index.ts
│   │   │   │   └── tracks/
│   │   │   │       ├── api/
│   │   │   │       │   ├── index.ts
│   │   │   │       │   ├── mocks.ts
│   │   │   │       │   ├── tracksApi.ts
│   │   │   │       │   └── tracksApi.types.ts
│   │   │   │       ├── constants/
│   │   │   │       │   └── index.ts
│   │   │   │       ├── index.ts
│   │   │   │       ├── model/
│   │   │   │       │   ├── hooks/
│   │   │   │       │   │   ├── index.ts
│   │   │   │       │   │   ├── useCreateTrackModal.ts
│   │   │   │       │   │   └── useEditTrackModal.ts
│   │   │   │       │   ├── index.ts
│   │   │   │       │   └── tracks-slice.ts
│   │   │   │       ├── ui/
│   │   │   │       │   ├── CreateEditTrackModal/
│   │   │   │       │   │   ├── CreateEditTrackModal.module.css
│   │   │   │       │   │   ├── CreateEditTrackModal.tsx
│   │   │   │       │   │   └── index.ts
│   │   │   │       │   ├── TrackActions/
│   │   │   │       │   │   ├── TrackActions.tsx
│   │   │   │       │   │   ├── TrackActionsMenu/
│   │   │   │       │   │   │   ├── TrackActionsMenu.tsx
│   │   │   │       │   │   │   └── index.ts
│   │   │   │       │   │   └── index.ts
│   │   │   │       │   ├── TrackCard/
│   │   │   │       │   │   ├── TrackCard.module.css
│   │   │   │       │   │   ├── TrackCard.stories.tsx
│   │   │   │       │   │   ├── TrackCard.tsx
│   │   │   │       │   │   └── index.ts
│   │   │   │       │   ├── TrackInfoCell/
│   │   │   │       │   │   ├── TrackInfoCell.module.css
│   │   │   │       │   │   ├── TrackInfoCell.tsx
│   │   │   │       │   │   └── index.ts
│   │   │   │       │   ├── TrackOverview/
│   │   │   │       │   │   ├── TrackOverview.module.css
│   │   │   │       │   │   ├── TrackOverview.stories.tsx
│   │   │   │       │   │   ├── TrackOverview.tsx
│   │   │   │       │   │   └── index.ts
│   │   │   │       │   ├── TrackRow/
│   │   │   │       │   │   ├── TrackRow.module.css
│   │   │   │       │   │   └── TrackRow.tsx
│   │   │   │       │   ├── TrackRowContainer/
│   │   │   │       │   │   ├── TrackRowContainer.tsx
│   │   │   │       │   │   └── index.ts
│   │   │   │       │   ├── TracksTable/
│   │   │   │       │   │   ├── TrackTable.stories.tsx
│   │   │   │       │   │   ├── TracksTable.tsx
│   │   │   │       │   │   └── index.ts
│   │   │   │       │   ├── TracksTableSkeleton/
│   │   │   │       │   │   ├── TracksTableSkeleton.tsx
│   │   │   │       │   │   └── index.ts
│   │   │   │       │   └── index.ts
│   │   │   │       └── utils/
│   │   │   │           └── playlistSync.ts
│   │   │   ├── layout/
│   │   │   │   ├── AppLoader/
│   │   │   │   │   ├── AppLoader.tsx
│   │   │   │   │   └── index.ts
│   │   │   │   ├── Header/
│   │   │   │   │   ├── AccountMenu/
│   │   │   │   │   │   ├── AccountMenu.module.css
│   │   │   │   │   │   ├── AccountMenu.stories.tsx
│   │   │   │   │   │   ├── AccountMenu.tsx
│   │   │   │   │   │   └── index.ts
│   │   │   │   │   ├── Header.module.css
│   │   │   │   │   ├── Header.tsx
│   │   │   │   │   └── index.ts
│   │   │   │   ├── Layout.module.css
│   │   │   │   ├── Layout.tsx
│   │   │   │   ├── Sidebar/
│   │   │   │   │   ├── MenuLinks/
│   │   │   │   │   │   ├── MenuLinks.module.css
│   │   │   │   │   │   ├── MenuLinks.tsx
│   │   │   │   │   │   └── index.ts
│   │   │   │   │   ├── Sidebar.module.css
│   │   │   │   │   ├── Sidebar.tsx
│   │   │   │   │   └── index.ts
│   │   │   │   └── index.ts
│   │   │   ├── main.tsx
│   │   │   ├── pages/
│   │   │   │   ├── MainPage/
│   │   │   │   │   ├── MainPage.module.css
│   │   │   │   │   ├── MainPage.tsx
│   │   │   │   │   └── index.ts
│   │   │   │   ├── PlaylistPage/
│   │   │   │   │   ├── PlaylistPage.module.css
│   │   │   │   │   ├── PlaylistPage.tsx
│   │   │   │   │   ├── index.ts
│   │   │   │   │   └── ui/
│   │   │   │   │       ├── ControlPanel/
│   │   │   │   │       │   ├── ControlPanel.module.css
│   │   │   │   │       │   ├── ControlPanel.tsx
│   │   │   │   │       │   └── index.ts
│   │   │   │   │       └── PlaylistPageSkeleton/
│   │   │   │   │           ├── PlaylistPageSkeleton.module.css
│   │   │   │   │           ├── PlaylistPageSkeleton.tsx
│   │   │   │   │           └── index.ts
│   │   │   │   ├── PlaylistsPage/
│   │   │   │   │   ├── PlaylistsPage.module.css
│   │   │   │   │   ├── PlaylistsPage.tsx
│   │   │   │   │   └── index.ts
│   │   │   │   ├── TrackLyricsPage/
│   │   │   │   │   ├── TrackLyricsPage.module.css
│   │   │   │   │   ├── TrackLyricsPage.tsx
│   │   │   │   │   └── index.ts
│   │   │   │   ├── TrackPage/
│   │   │   │   │   ├── TrackPage.module.css
│   │   │   │   │   ├── TrackPage.tsx
│   │   │   │   │   ├── index.ts
│   │   │   │   │   └── ui/
│   │   │   │   │       ├── ControlPanel/
│   │   │   │   │       │   ├── ControlPanel.module.css
│   │   │   │   │       │   ├── ControlPanel.tsx
│   │   │   │   │       │   └── index.ts
│   │   │   │   │       └── TrackPageSkeleton/
│   │   │   │   │           ├── TrackPageSkeleton.module.css
│   │   │   │   │           ├── TrackPageSkeleton.tsx
│   │   │   │   │           └── index.ts
│   │   │   │   ├── TracksPage/
│   │   │   │   │   ├── TracksPage.module.css
│   │   │   │   │   ├── TracksPage.tsx
│   │   │   │   │   └── index.ts
│   │   │   │   ├── UserPage/
│   │   │   │   │   ├── UserPage.module.css
│   │   │   │   │   ├── UserPage.tsx
│   │   │   │   │   ├── hooks/
│   │   │   │   │   │   ├── index.ts
│   │   │   │   │   │   ├── useOwnerData.ts
│   │   │   │   │   │   └── useUserPageBackgroundColor.ts
│   │   │   │   │   ├── index.ts
│   │   │   │   │   └── ui/
│   │   │   │   │       ├── UserInfo/
│   │   │   │   │       │   ├── UserInfo.module.css
│   │   │   │   │       │   ├── UserInfo.tsx
│   │   │   │   │       │   ├── UserInfoSkeleton/
│   │   │   │   │       │   │   ├── UserInfoSkeleton.module.css
│   │   │   │   │       │   │   ├── UserInfoSkeleton.tsx
│   │   │   │   │       │   │   └── index.ts
│   │   │   │   │       │   ├── UserStats/
│   │   │   │   │       │   │   ├── UserStats.module.css
│   │   │   │   │       │   │   ├── UserStats.tsx
│   │   │   │   │       │   │   └── index.ts
│   │   │   │   │       │   └── index.ts
│   │   │   │   │       ├── UserTabs/
│   │   │   │   │       │   ├── LikedTracksTab/
│   │   │   │   │       │   │   ├── LikedTracksTab.module.css
│   │   │   │   │       │   │   ├── LikedTracksTab.tsx
│   │   │   │   │       │   │   └── index.ts
│   │   │   │   │       │   ├── MyLikedPlaylistsTab/
│   │   │   │   │       │   │   ├── MyLikedPlaylistsTab.module.css
│   │   │   │   │       │   │   ├── MyLikedPlaylistsTab.tsx
│   │   │   │   │       │   │   └── index.ts
│   │   │   │   │       │   ├── PlaylistsTab/
│   │   │   │   │       │   │   ├── PlaylistsTab.module.css
│   │   │   │   │       │   │   ├── PlaylistsTab.tsx
│   │   │   │   │       │   │   └── index.ts
│   │   │   │   │       │   ├── TracksTab/
│   │   │   │   │       │   │   ├── TracksTab.module.css
│   │   │   │   │       │   │   ├── TracksTab.tsx
│   │   │   │   │       │   │   └── index.ts
│   │   │   │   │       │   ├── UserTabs.tsx
│   │   │   │   │       │   ├── UserTabsSkeleton/
│   │   │   │   │       │   │   ├── UserTabsSkeleton.module.css
│   │   │   │   │       │   │   ├── UserTabsSkeleton.tsx
│   │   │   │   │       │   │   └── index.ts
│   │   │   │   │       │   └── index.ts
│   │   │   │   │       └── index.ts
│   │   │   │   ├── common/
│   │   │   │   │   ├── hooks/
│   │   │   │   │   │   ├── index.ts
│   │   │   │   │   │   ├── usePageBackgroundColor.ts
│   │   │   │   │   │   └── usePageSearchParams.ts
│   │   │   │   │   ├── index.ts
│   │   │   │   │   └── ui/
│   │   │   │   │       ├── ContentList/
│   │   │   │   │       │   ├── ContentList.module.css
│   │   │   │   │       │   ├── ContentList.tsx
│   │   │   │   │       │   └── index.ts
│   │   │   │   │       ├── PageWithHeader/
│   │   │   │   │       │   ├── PageWithHeader.module.css
│   │   │   │   │       │   ├── PageWithHeader.tsx
│   │   │   │   │       │   └── index.ts
│   │   │   │   │       ├── PageWithoutHeader/
│   │   │   │   │       │   ├── PageWithoutHeader.module.css
│   │   │   │   │       │   ├── PageWithoutHeader.tsx
│   │   │   │   │       │   └── index.ts
│   │   │   │   │       ├── SearchTags/
│   │   │   │   │       │   ├── SearchTags.tsx
│   │   │   │   │       │   └── index.ts
│   │   │   │   │       ├── SearchTextField/
│   │   │   │   │       │   ├── SearchTextField.tsx
│   │   │   │   │       │   └── index.ts
│   │   │   │   │       └── SortSelect/
│   │   │   │   │           ├── SortSelect.module.css
│   │   │   │   │           ├── SortSelect.tsx
│   │   │   │   │           └── index.ts
│   │   │   │   └── index.ts
│   │   │   ├── player/
│   │   │   │   ├── MIGRATION_GUIDE.md
│   │   │   │   ├── README.md
│   │   │   │   ├── SPECIFICATION.md
│   │   │   │   ├── index.ts
│   │   │   │   ├── player.ts
│   │   │   │   ├── playerHooks.ts
│   │   │   │   ├── playerMiddleware.ts
│   │   │   │   ├── playerSelectors.ts
│   │   │   │   ├── playerSlice.ts
│   │   │   │   ├── task.md
│   │   │   │   ├── types/
│   │   │   │   │   └── player.types.ts
│   │   │   │   └── utils/
│   │   │   │       ├── convert-api-track-to-player-track.ts
│   │   │   │       ├── format-time.ts
│   │   │   │       ├── index.ts
│   │   │   │       ├── shuffle.ts
│   │   │   │       └── throttle.ts
│   │   │   ├── shared/
│   │   │   │   ├── assets/
│   │   │   │   │   └── images/
│   │   │   │   │       └── no-cover-placeholder.avif
│   │   │   │   ├── components/
│   │   │   │   │   ├── AudioPlayer/
│   │   │   │   │   │   ├── AudioPlayer.module.css
│   │   │   │   │   │   ├── AudioPlayer.stories.tsx
│   │   │   │   │   │   ├── AudioPlayer.tsx
│   │   │   │   │   │   ├── AudioPlayerSceleton/
│   │   │   │   │   │   │   ├── AudioPlayerSkeleton.module.css
│   │   │   │   │   │   │   ├── AudioPlayerSkeleton.stories.tsx
│   │   │   │   │   │   │   └── AudioPlayerSkeleton.tsx
│   │   │   │   │   │   └── index.ts
│   │   │   │   │   ├── Autocomplete/
│   │   │   │   │   │   ├── Autocomplete.module.css
│   │   │   │   │   │   ├── Autocomplete.stories.tsx
│   │   │   │   │   │   ├── Autocomplete.tsx
│   │   │   │   │   │   └── index.ts
│   │   │   │   │   ├── Avatar/
│   │   │   │   │   │   ├── Avatar.module.css
│   │   │   │   │   │   ├── Avatar.stories.tsx
│   │   │   │   │   │   ├── Avatar.tsx
│   │   │   │   │   │   └── index.ts
│   │   │   │   │   ├── Button/
│   │   │   │   │   │   ├── Button.module.css
│   │   │   │   │   │   ├── Button.stories.tsx
│   │   │   │   │   │   ├── Button.tsx
│   │   │   │   │   │   └── index.ts
│   │   │   │   │   ├── Card/
│   │   │   │   │   │   ├── Card.module.css
│   │   │   │   │   │   ├── Card.stories.tsx
│   │   │   │   │   │   ├── Card.tsx
│   │   │   │   │   │   └── index.ts
│   │   │   │   │   ├── Dialog/
│   │   │   │   │   │   ├── Dialog.module.css
│   │   │   │   │   │   ├── Dialog.stories.tsx
│   │   │   │   │   │   ├── Dialog.tsx
│   │   │   │   │   │   └── index.ts
│   │   │   │   │   ├── DropdownMenu/
│   │   │   │   │   │   ├── DropdownMenu.module.css
│   │   │   │   │   │   ├── DropdownMenu.stories.tsx
│   │   │   │   │   │   ├── DropdownMenu.tsx
│   │   │   │   │   │   └── index.ts
│   │   │   │   │   ├── FileUploader/
│   │   │   │   │   │   ├── FileUploader.module.css
│   │   │   │   │   │   ├── FileUploader.stories.tsx
│   │   │   │   │   │   ├── FileUploader.tsx
│   │   │   │   │   │   └── index.ts
│   │   │   │   │   ├── FormControlledTextField/
│   │   │   │   │   │   ├── FormControlledTextField.tsx
│   │   │   │   │   │   └── index.ts
│   │   │   │   │   ├── Hashtag/
│   │   │   │   │   │   ├── Tag.module.css
│   │   │   │   │   │   ├── Tag.stories.tsx
│   │   │   │   │   │   ├── Tag.tsx
│   │   │   │   │   │   └── index.ts
│   │   │   │   │   ├── IconButton/
│   │   │   │   │   │   ├── IconButton.module.css
│   │   │   │   │   │   ├── IconButton.stories.tsx
│   │   │   │   │   │   ├── IconButton.tsx
│   │   │   │   │   │   └── index.ts
│   │   │   │   │   ├── ImageCropper/
│   │   │   │   │   │   ├── ImageCropper.module.css
│   │   │   │   │   │   ├── ImageCropper.stories.tsx
│   │   │   │   │   │   ├── ImageCropper.tsx
│   │   │   │   │   │   └── index.ts
│   │   │   │   │   ├── ImageUploader/
│   │   │   │   │   │   ├── ImageUploader.module.css
│   │   │   │   │   │   ├── ImageUploader.stories.tsx
│   │   │   │   │   │   ├── ImageUploader.tsx
│   │   │   │   │   │   └── index.ts
│   │   │   │   │   ├── Loader/
│   │   │   │   │   │   ├── Loader.module.css
│   │   │   │   │   │   ├── Loader.tsx
│   │   │   │   │   │   └── index.ts
│   │   │   │   │   ├── Pagination/
│   │   │   │   │   │   ├── Pagination.module.css
│   │   │   │   │   │   ├── Pagination.stories.tsx
│   │   │   │   │   │   ├── Pagination.tsx
│   │   │   │   │   │   └── index.ts
│   │   │   │   │   ├── Progress/
│   │   │   │   │   │   ├── Progress.module.css
│   │   │   │   │   │   ├── Progress.stories.tsx
│   │   │   │   │   │   ├── Progress.tsx
│   │   │   │   │   │   └── index.ts
│   │   │   │   │   ├── ReactionButtons/
│   │   │   │   │   │   ├── ReactionButtons.module.css
│   │   │   │   │   │   ├── ReactionButtons.stories.tsx
│   │   │   │   │   │   ├── ReactionButtons.tsx
│   │   │   │   │   │   └── index.ts
│   │   │   │   │   ├── SearchField/
│   │   │   │   │   │   ├── SearchField.module.css
│   │   │   │   │   │   ├── SearchField.stories.tsx
│   │   │   │   │   │   ├── SearchField.tsx
│   │   │   │   │   │   └── index.ts
│   │   │   │   │   ├── Select/
│   │   │   │   │   │   ├── Select.module.css
│   │   │   │   │   │   ├── Select.stories.tsx
│   │   │   │   │   │   ├── Select.tsx
│   │   │   │   │   │   └── index.ts
│   │   │   │   │   ├── Skeleton/
│   │   │   │   │   │   ├── Skeleton.module.css
│   │   │   │   │   │   ├── Skeleton.stories.tsx
│   │   │   │   │   │   ├── Skeleton.tsx
│   │   │   │   │   │   └── index.ts
│   │   │   │   │   ├── SortSelect/
│   │   │   │   │   │   └── Select.tsx
│   │   │   │   │   ├── Spinner/
│   │   │   │   │   │   ├── Spinner.stories.tsx
│   │   │   │   │   │   ├── Spinner.tsx
│   │   │   │   │   │   └── spinner.module.css
│   │   │   │   │   ├── Table/
│   │   │   │   │   │   ├── Table.module.css
│   │   │   │   │   │   ├── Table.stories.tsx
│   │   │   │   │   │   ├── Table.tsx
│   │   │   │   │   │   └── index.ts
│   │   │   │   │   ├── Tabs/
│   │   │   │   │   │   ├── Tabs.module.css
│   │   │   │   │   │   ├── Tabs.stories.tsx
│   │   │   │   │   │   ├── Tabs.tsx
│   │   │   │   │   │   └── index.ts
│   │   │   │   │   ├── TagEditor/
│   │   │   │   │   │   ├── TagEditor.module.css
│   │   │   │   │   │   ├── TagEditor.stories.tsx
│   │   │   │   │   │   ├── TagEditor.tsx
│   │   │   │   │   │   └── index.ts
│   │   │   │   │   ├── TextField/
│   │   │   │   │   │   ├── TextField.module.css
│   │   │   │   │   │   ├── TextField.stories.tsx
│   │   │   │   │   │   ├── TextField.tsx
│   │   │   │   │   │   └── index.ts
│   │   │   │   │   ├── Textarea/
│   │   │   │   │   │   ├── Textarea.module.css
│   │   │   │   │   │   ├── Textarea.stories.tsx
│   │   │   │   │   │   ├── Textarea.tsx
│   │   │   │   │   │   └── index.ts
│   │   │   │   │   ├── Typography/
│   │   │   │   │   │   ├── Typography.module.css
│   │   │   │   │   │   ├── Typography.stories.tsx
│   │   │   │   │   │   ├── Typography.tsx
│   │   │   │   │   │   └── index.ts
│   │   │   │   │   └── index.ts
│   │   │   │   ├── configs/
│   │   │   │   │   ├── index.ts
│   │   │   │   │   └── paths.ts
│   │   │   │   ├── constants/
│   │   │   │   │   ├── constants.ts
│   │   │   │   │   └── index.ts
│   │   │   │   ├── hooks/
│   │   │   │   │   ├── index.ts
│   │   │   │   │   ├── useAppDispatch.ts
│   │   │   │   │   ├── useAppSelector.ts
│   │   │   │   │   ├── useCurrentPage.ts
│   │   │   │   │   ├── useDebounce.ts
│   │   │   │   │   ├── useGetId.ts
│   │   │   │   │   ├── useGlobalLoading.ts
│   │   │   │   │   └── useHover.ts
│   │   │   │   ├── icons/
│   │   │   │   │   ├── AddToPlaylistIcon.tsx
│   │   │   │   │   ├── AddTrackIcon.tsx
│   │   │   │   │   ├── ArrowBackIcon.tsx
│   │   │   │   │   ├── ArrowDownIcon.tsx
│   │   │   │   │   ├── CheckedIcon.tsx
│   │   │   │   │   ├── ClockIcon.tsx
│   │   │   │   │   ├── CreateIcon.tsx
│   │   │   │   │   ├── DeleteIcon.tsx
│   │   │   │   │   ├── DeleteTagIconButton.tsx
│   │   │   │   │   ├── DislikeIcon.tsx
│   │   │   │   │   ├── DownloadIcon.tsx
│   │   │   │   │   ├── EditIcon.tsx
│   │   │   │   │   ├── HomeIcon.tsx
│   │   │   │   │   ├── IconOneRepeat.tsx
│   │   │   │   │   ├── ImageUploadIcon.tsx
│   │   │   │   │   ├── KeyboardArrowLeftIcon.tsx
│   │   │   │   │   ├── KeyboardArrowRightIcon.tsx
│   │   │   │   │   ├── LanguageIcon.tsx
│   │   │   │   │   ├── LibraryIcon.tsx
│   │   │   │   │   ├── LikeIcon.tsx
│   │   │   │   │   ├── LikeIconFill.tsx
│   │   │   │   │   ├── LikeInSquareIcon.tsx
│   │   │   │   │   ├── LiveWaveIcon/
│   │   │   │   │   │   ├── LiveWaveIcon.module.css
│   │   │   │   │   │   ├── LiveWaveIcon.tsx
│   │   │   │   │   │   └── index.ts
│   │   │   │   │   ├── LogoutIcon.tsx
│   │   │   │   │   ├── MoreIcon.tsx
│   │   │   │   │   ├── PauseIcon.tsx
│   │   │   │   │   ├── PlayIcon.tsx
│   │   │   │   │   ├── PlaylistIcon.tsx
│   │   │   │   │   ├── PlusIcon.tsx
│   │   │   │   │   ├── ProfileIcon.tsx
│   │   │   │   │   ├── RepeatIcon.tsx
│   │   │   │   │   ├── SearchIcon.tsx
│   │   │   │   │   ├── ShuffleIcon.tsx
│   │   │   │   │   ├── SkipNextIcon.tsx
│   │   │   │   │   ├── SkipPreviousIcon.tsx
│   │   │   │   │   ├── StaticWaveIcon.tsx
│   │   │   │   │   ├── TextIcon.tsx
│   │   │   │   │   ├── TrackIcon.tsx
│   │   │   │   │   ├── UncheckedIcon.tsx
│   │   │   │   │   ├── UploadIcon.tsx
│   │   │   │   │   ├── VolumeIcon.tsx
│   │   │   │   │   ├── VolumeMuteIcon.tsx
│   │   │   │   │   └── index.ts
│   │   │   │   ├── translations/
│   │   │   │   │   ├── i18nConfiguration.ts
│   │   │   │   │   └── languages/
│   │   │   │   │       ├── en.json
│   │   │   │   │       └── ru.json
│   │   │   │   ├── types/
│   │   │   │   │   ├── common.types.ts
│   │   │   │   │   ├── commonApi.types.ts
│   │   │   │   │   └── index.ts
│   │   │   │   └── utils/
│   │   │   │       ├── build-query-string.ts
│   │   │   │       ├── convert-file-to-base-64.ts
│   │   │   │       ├── decode-file-from-base-64.ts
│   │   │   │       ├── format-created-date.ts
│   │   │   │       ├── get-image-by-type.ts
│   │   │   │       ├── get-plural-key.ts
│   │   │   │       ├── get-russian-plural-form.ts
│   │   │   │       ├── get-user-initials.ts
│   │   │   │       ├── index.ts
│   │   │   │       ├── set-locale.ts
│   │   │   │       └── show-error-toast.ts
│   │   │   ├── styles/
│   │   │   │   ├── fonts.css
│   │   │   │   ├── global.css
│   │   │   │   ├── reset.css
│   │   │   │   └── variables.css
│   │   │   ├── vite-env.d.ts
│   │   │   └── widgets/
│   │   │       └── Player/
│   │   │           ├── Player.module.css
│   │   │           ├── Player.tsx
│   │   │           └── index.ts
│   │   ├── stylelint.config.js
│   │   ├── tsconfig.app.json
│   │   ├── tsconfig.json
│   │   ├── tsconfig.node.json
│   │   └── vite.config.ts
│   ├── tanstack-query-zustand/
│   │   ├── .claude/
│   │   │   └── skills/
│   │   │       └── i18n-rules/
│   │   │           └── SKILL.md
│   │   ├── .gitignore
│   │   ├── .storybook/
│   │   │   ├── main.ts
│   │   │   └── preview.tsx
│   │   ├── AGENTS.md
│   │   ├── CLAUDE.md
│   │   ├── README.md
│   │   ├── eslint.config.js
│   │   ├── index.html
│   │   ├── package.json
│   │   ├── src/
│   │   │   ├── App.css
│   │   │   ├── App.tsx
│   │   │   ├── app/
│   │   │   │   ├── App.tsx
│   │   │   │   ├── entrypoint/
│   │   │   │   │   └── main.tsx
│   │   │   │   ├── query-client/
│   │   │   │   │   └── query-client.tsx
│   │   │   │   ├── routing/
│   │   │   │   │   ├── Routing.tsx
│   │   │   │   │   └── index.ts
│   │   │   │   └── styles/
│   │   │   │       ├── fonts.css
│   │   │   │       ├── global.css
│   │   │   │       ├── reset.css
│   │   │   │       └── variables.css
│   │   │   ├── assets/
│   │   │   │   └── img/
│   │   │   │       └── no-cover-placeholder.avif
│   │   │   ├── entities/
│   │   │   │   └── playlist/
│   │   │   │       ├── index.tsx
│   │   │   │       └── ui/
│   │   │   │           ├── PlaylistCard/
│   │   │   │           │   ├── PlaylistCard.module.scss
│   │   │   │           │   ├── PlaylistCard.stories.tsx
│   │   │   │           │   ├── PlaylistCard.tsx
│   │   │   │           │   └── index.ts
│   │   │   │           ├── PlaylistCardSkeleton/
│   │   │   │           │   ├── PlaylistCardSkeleton.tsx
│   │   │   │           │   └── index.ts
│   │   │   │           └── PlaylistItem/
│   │   │   │               ├── PlaylistItem.tsx
│   │   │   │               ├── PlaylistItem.types.ts
│   │   │   │               └── index.ts
│   │   │   ├── features/
│   │   │   │   ├── artists/
│   │   │   │   │   ├── api/
│   │   │   │   │   │   ├── artists-api.ts
│   │   │   │   │   │   ├── index.ts
│   │   │   │   │   │   └── use-artists.query.ts
│   │   │   │   │   ├── index.ts
│   │   │   │   │   └── ui/
│   │   │   │   │       └── ArtistCard/
│   │   │   │   │           ├── ArtistCard.module.css
│   │   │   │   │           ├── ArtistCard.stories.tsx
│   │   │   │   │           ├── ArtistCard.tsx
│   │   │   │   │           └── index.ts
│   │   │   │   ├── auth/
│   │   │   │   │   ├── api/
│   │   │   │   │   │   ├── use-login.mutation.ts
│   │   │   │   │   │   ├── use-logout.mutation.ts
│   │   │   │   │   │   └── use-me.query.ts
│   │   │   │   │   ├── index.ts
│   │   │   │   │   ├── types/
│   │   │   │   │   │   └── auth-api.types.ts
│   │   │   │   │   └── ui/
│   │   │   │   │       ├── LoginButtonAndModal/
│   │   │   │   │       │   ├── LoginButtonAndModal.tsx
│   │   │   │   │       │   └── index.ts
│   │   │   │   │       ├── LoginModal/
│   │   │   │   │       │   ├── LoginModal.module.css
│   │   │   │   │       │   ├── LoginModal.tsx
│   │   │   │   │       │   └── index.ts
│   │   │   │   │       ├── ProfileDropdownMenu/
│   │   │   │   │       │   ├── ProfileDropdownMenu.module.css
│   │   │   │   │       │   ├── ProfileDropdownMenu.stories.tsx
│   │   │   │   │       │   ├── ProfileDropdownMenu.tsx
│   │   │   │   │       │   └── index.ts
│   │   │   │   │       └── index.ts
│   │   │   │   ├── playlists/
│   │   │   │   │   ├── api/
│   │   │   │   │   │   ├── index.ts
│   │   │   │   │   │   ├── playlistsApi.ts
│   │   │   │   │   │   ├── query-key-factory.ts
│   │   │   │   │   │   ├── types.ts
│   │   │   │   │   │   ├── use-playlist-mutations.ts
│   │   │   │   │   │   ├── use-playlist.query.ts
│   │   │   │   │   │   └── use-playlists.query.ts
│   │   │   │   │   ├── index.ts
│   │   │   │   │   ├── model/
│   │   │   │   │   │   └── usePlaylistReactions.ts
│   │   │   │   │   └── ui/
│   │   │   │   │       ├── ChoosePlaylistModal/
│   │   │   │   │       │   ├── ChoosePlaylistModal.module.css
│   │   │   │   │       │   └── ChoosePlaylistModal.tsx
│   │   │   │   │       ├── CreatePlaylistModal/
│   │   │   │   │       │   ├── CreatePlaylistModal.module.css
│   │   │   │   │       │   ├── CreatePlaylistModal.tsx
│   │   │   │   │       │   └── index.ts
│   │   │   │   │       ├── PlaylistOverview/
│   │   │   │   │       │   ├── PlaylistOverview.module.css
│   │   │   │   │       │   ├── PlaylistOverview.stories.tsx
│   │   │   │   │       │   ├── PlaylistOverview.tsx
│   │   │   │   │       │   └── index.ts
│   │   │   │   │       ├── PlaylistRow/
│   │   │   │   │       │   ├── PlaylistRow.module.css
│   │   │   │   │       │   ├── PlaylistRow.tsx
│   │   │   │   │       │   └── index.ts
│   │   │   │   │       └── index.ts
│   │   │   │   ├── profile/
│   │   │   │   │   ├── config/
│   │   │   │   │   │   ├── empty-profile.ts
│   │   │   │   │   │   └── index.ts
│   │   │   │   │   ├── index.ts
│   │   │   │   │   ├── model/
│   │   │   │   │   │   ├── hooks/
│   │   │   │   │   │   │   ├── index.ts
│   │   │   │   │   │   │   ├── use-edit-profile-modal.ts
│   │   │   │   │   │   │   ├── use-edit-profile-schema.ts
│   │   │   │   │   │   │   └── use-hydrate-profile.ts
│   │   │   │   │   │   ├── index.ts
│   │   │   │   │   │   ├── profile-schemas.ts
│   │   │   │   │   │   └── profile-store.ts
│   │   │   │   │   ├── types/
│   │   │   │   │   │   ├── index.ts
│   │   │   │   │   │   └── profile.types.ts
│   │   │   │   │   ├── ui/
│   │   │   │   │   │   ├── EditProfileModal/
│   │   │   │   │   │   │   ├── EditProfileModal.module.css
│   │   │   │   │   │   │   ├── EditProfileModal.tsx
│   │   │   │   │   │   │   └── index.ts
│   │   │   │   │   │   └── index.ts
│   │   │   │   │   └── utils/
│   │   │   │   │       ├── index.ts
│   │   │   │   │       ├── profile-storage.ts
│   │   │   │   │       └── storage-key.ts
│   │   │   │   ├── tags/
│   │   │   │   │   ├── api/
│   │   │   │   │   │   ├── index.ts
│   │   │   │   │   │   ├── tags-api.ts
│   │   │   │   │   │   └── use-tags.query.ts
│   │   │   │   │   ├── index.ts
│   │   │   │   │   └── ui/
│   │   │   │   │       ├── TagsList/
│   │   │   │   │       │   ├── TagsList.module.css
│   │   │   │   │       │   ├── TagsList.stories.tsx
│   │   │   │   │       │   ├── TagsList.tsx
│   │   │   │   │       │   └── index.ts
│   │   │   │   │       └── index.ts
│   │   │   │   └── tracks/
│   │   │   │       ├── api/
│   │   │   │       │   ├── index.ts
│   │   │   │       │   ├── query-key-factory.ts
│   │   │   │       │   ├── tracksApi.ts
│   │   │   │       │   ├── types.ts
│   │   │   │       │   ├── use-playlist-tracks.query.ts
│   │   │   │       │   ├── use-track-mutations.ts
│   │   │   │       │   ├── use-track.query.ts
│   │   │   │       │   └── use-tracks.query.ts
│   │   │   │       ├── index.ts
│   │   │   │       ├── model/
│   │   │   │       │   └── useTrackReactions.ts
│   │   │   │       ├── ui/
│   │   │   │       │   ├── CreateTrackForm/
│   │   │   │       │   │   ├── CreateTrackModal.module.css
│   │   │   │       │   │   └── CreateTrackModal.tsx
│   │   │   │       │   ├── TrackActions/
│   │   │   │       │   │   ├── TrackActions.tsx
│   │   │   │       │   │   └── index.ts
│   │   │   │       │   ├── TrackActionsMenu/
│   │   │   │       │   │   └── TrackActionsMenu.tsx
│   │   │   │       │   ├── TrackCard/
│   │   │   │       │   │   ├── TrackCard.module.css
│   │   │   │       │   │   ├── TrackCard.stories.tsx
│   │   │   │       │   │   ├── TrackCard.tsx
│   │   │   │       │   │   └── index.ts
│   │   │   │       │   ├── TrackInfoCell/
│   │   │   │       │   │   ├── TrackInfoCell.module.css
│   │   │   │       │   │   ├── TrackInfoCell.tsx
│   │   │   │       │   │   └── index.ts
│   │   │   │       │   ├── TrackOverview/
│   │   │   │       │   │   ├── TrackOverview.module.css
│   │   │   │       │   │   ├── TrackOverview.stories.tsx
│   │   │   │       │   │   ├── TrackOverview.tsx
│   │   │   │       │   │   └── index.ts
│   │   │   │       │   ├── TrackRow/
│   │   │   │       │   │   ├── TrackRow.module.css
│   │   │   │       │   │   └── TrackRow.tsx
│   │   │   │       │   ├── TrackRowContainer/
│   │   │   │       │   │   ├── TrackRowContainer.module.css
│   │   │   │       │   │   └── TrackRowContainer.tsx
│   │   │   │       │   ├── TracksTable/
│   │   │   │       │   │   ├── TrackTable.stories.tsx
│   │   │   │       │   │   ├── TracksTable.tsx
│   │   │   │       │   │   └── index.ts
│   │   │   │       │   ├── TracksTableSkeleton/
│   │   │   │       │   │   ├── TracksTableSkeleton.tsx
│   │   │   │       │   │   └── index.ts
│   │   │   │       │   └── index.ts
│   │   │   │       └── utils/
│   │   │   │           └── playlistSync.ts
│   │   │   ├── index.css
│   │   │   ├── layout/
│   │   │   │   ├── Header/
│   │   │   │   │   ├── Header.module.css
│   │   │   │   │   ├── Header.tsx
│   │   │   │   │   └── index.ts
│   │   │   │   ├── Layout.module.css
│   │   │   │   ├── Layout.tsx
│   │   │   │   ├── Sidebar/
│   │   │   │   │   ├── MenuLinks/
│   │   │   │   │   │   ├── MenuLinks.module.css
│   │   │   │   │   │   ├── MenuLinks.tsx
│   │   │   │   │   │   └── index.ts
│   │   │   │   │   ├── Sidebar.module.css
│   │   │   │   │   ├── Sidebar.tsx
│   │   │   │   │   └── index.ts
│   │   │   │   └── index.ts
│   │   │   ├── main.tsx
│   │   │   ├── pages/
│   │   │   │   ├── MainPage/
│   │   │   │   │   ├── MainPage.module.css
│   │   │   │   │   ├── MainPage.tsx
│   │   │   │   │   └── index.ts
│   │   │   │   ├── PlaylistPage/
│   │   │   │   │   ├── PlaylistPage.module.css
│   │   │   │   │   ├── PlaylistPage.tsx
│   │   │   │   │   ├── index.ts
│   │   │   │   │   └── ui/
│   │   │   │   │       ├── ControlPanel/
│   │   │   │   │       │   ├── ControlPanel.module.scss
│   │   │   │   │       │   ├── ControlPanel.tsx
│   │   │   │   │       │   └── index.ts
│   │   │   │   │       └── PlaylistPageSkeleton/
│   │   │   │   │           ├── PlaylistPageSkeleton.module.css
│   │   │   │   │           ├── PlaylistPageSkeleton.tsx
│   │   │   │   │           └── index.ts
│   │   │   │   ├── PlaylistsPage/
│   │   │   │   │   ├── PlaylistsPage.module.css
│   │   │   │   │   ├── PlaylistsPage.tsx
│   │   │   │   │   ├── PlaylistsPage.types.ts
│   │   │   │   │   ├── index.ts
│   │   │   │   │   └── model/
│   │   │   │   │       ├── useCreatePlaylist.ts
│   │   │   │   │       ├── useDeletePlaylist.ts
│   │   │   │   │       └── useUploadPlaylistCover.ts
│   │   │   │   ├── TrackLyricsPage/
│   │   │   │   │   ├── TrackLyricsPage.module.css
│   │   │   │   │   ├── TrackLyricsPage.tsx
│   │   │   │   │   └── index.ts
│   │   │   │   ├── TrackPage/
│   │   │   │   │   ├── TrackPage.module.css
│   │   │   │   │   ├── TrackPage.tsx
│   │   │   │   │   ├── index.ts
│   │   │   │   │   └── ui/
│   │   │   │   │       ├── ControlPanel/
│   │   │   │   │       │   ├── ControlPanel.module.css
│   │   │   │   │       │   ├── ControlPanel.tsx
│   │   │   │   │       │   └── index.ts
│   │   │   │   │       └── TrackPageSkeleton/
│   │   │   │   │           ├── TrackPageSkeleton.module.css
│   │   │   │   │           ├── TrackPageSkeleton.tsx
│   │   │   │   │           └── index.ts
│   │   │   │   ├── TracksPage/
│   │   │   │   │   ├── TracksPage.module.css
│   │   │   │   │   ├── TracksPage.tsx
│   │   │   │   │   ├── TracksSortFunction.ts
│   │   │   │   │   ├── index.ts
│   │   │   │   │   ├── model/
│   │   │   │   │   │   ├── useTrackDetails.ts
│   │   │   │   │   │   ├── useTracksInfinityQuery.ts
│   │   │   │   │   │   ├── useTracksQuery.tsx
│   │   │   │   │   │   ├── useUploadTrack.ts
│   │   │   │   │   │   └── useUploadTrackCover.ts
│   │   │   │   │   └── tracksPageTypes/
│   │   │   │   │       └── TracksPageTypes.ts
│   │   │   │   ├── UserPage/
│   │   │   │   │   ├── UserPage.module.css
│   │   │   │   │   ├── UserPage.tsx
│   │   │   │   │   ├── hooks/
│   │   │   │   │   │   ├── index.ts
│   │   │   │   │   │   ├── useUserPageBackgroundColor.ts
│   │   │   │   │   │   └── useUserPageData.ts
│   │   │   │   │   ├── index.ts
│   │   │   │   │   └── ui/
│   │   │   │   │       ├── UserInfo/
│   │   │   │   │       │   ├── UserInfo.module.css
│   │   │   │   │       │   ├── UserInfo.tsx
│   │   │   │   │       │   ├── UserInfoSkeleton.module.css
│   │   │   │   │       │   ├── UserInfoSkeleton.tsx
│   │   │   │   │       │   ├── UserStats.module.css
│   │   │   │   │       │   ├── UserStats.tsx
│   │   │   │   │       │   └── index.ts
│   │   │   │   │       ├── UserTabs/
│   │   │   │   │       │   ├── LikedTracksTab/
│   │   │   │   │       │   │   ├── LikedTracksTab.module.css
│   │   │   │   │       │   │   ├── LikedTracksTab.tsx
│   │   │   │   │       │   │   └── index.ts
│   │   │   │   │       │   ├── MyLikedPlaylistsTab/
│   │   │   │   │       │   │   ├── MyLikedPlaylistsTab.module.css
│   │   │   │   │       │   │   ├── MyLikedPlaylistsTab.tsx
│   │   │   │   │       │   │   └── index.ts
│   │   │   │   │       │   ├── PlaylistsTab/
│   │   │   │   │       │   │   ├── PlaylistsTab.module.css
│   │   │   │   │       │   │   ├── PlaylistsTab.tsx
│   │   │   │   │       │   │   └── index.ts
│   │   │   │   │       │   ├── TracksTab/
│   │   │   │   │       │   │   ├── TracksTab.module.css
│   │   │   │   │       │   │   ├── TracksTab.tsx
│   │   │   │   │       │   │   └── index.ts
│   │   │   │   │       │   ├── UserTabs.tsx
│   │   │   │   │       │   ├── UserTabsSkeleton/
│   │   │   │   │       │   │   ├── UserTabsSkeleton.module.css
│   │   │   │   │       │   │   ├── UserTabsSkeleton.tsx
│   │   │   │   │       │   │   └── index.ts
│   │   │   │   │       │   └── index.ts
│   │   │   │   │       └── index.ts
│   │   │   │   ├── auth/
│   │   │   │   │   └── OAuthRedirect/
│   │   │   │   │       ├── OAuthCallback.module.css
│   │   │   │   │       └── OAuthCallback.tsx
│   │   │   │   ├── common/
│   │   │   │   │   ├── ContentList/
│   │   │   │   │   │   ├── ContentList.module.css
│   │   │   │   │   │   ├── ContentList.tsx
│   │   │   │   │   │   └── index.ts
│   │   │   │   │   ├── PageWithHeader/
│   │   │   │   │   │   ├── PageWithHeader.module.css
│   │   │   │   │   │   └── PageWithHeader.tsx
│   │   │   │   │   ├── PageWithoutHeader/
│   │   │   │   │   │   ├── PageWithoutHeader.module.css
│   │   │   │   │   │   └── PageWithoutHeader.tsx
│   │   │   │   │   ├── PageWrapper/
│   │   │   │   │   │   ├── PageWrapper.module.css
│   │   │   │   │   │   ├── PageWrapper.tsx
│   │   │   │   │   │   └── index.ts
│   │   │   │   │   ├── SearchTextField/
│   │   │   │   │   │   ├── SearchTextField.tsx
│   │   │   │   │   │   └── index.ts
│   │   │   │   │   ├── SortSelect/
│   │   │   │   │   │   ├── SortSelect.module.css
│   │   │   │   │   │   ├── SortSelect.tsx
│   │   │   │   │   │   └── index.ts
│   │   │   │   │   └── index.ts
│   │   │   │   └── index.ts
│   │   │   ├── player/
│   │   │   │   ├── README.md
│   │   │   │   ├── SPECIFICATION.md
│   │   │   │   ├── index.ts
│   │   │   │   ├── model/
│   │   │   │   │   ├── audio-manager.ts
│   │   │   │   │   ├── player-hooks.ts
│   │   │   │   │   ├── player-store.ts
│   │   │   │   │   └── player-track-hooks.ts
│   │   │   │   ├── task.md
│   │   │   │   ├── types/
│   │   │   │   │   └── player.types.ts
│   │   │   │   └── utils/
│   │   │   │       ├── convert-api-track-to-player-track.ts
│   │   │   │       ├── format-time.ts
│   │   │   │       ├── index.ts
│   │   │   │       ├── shuffle.ts
│   │   │   │       └── track-navigation.ts
│   │   │   ├── shared/
│   │   │   │   ├── api/
│   │   │   │   │   ├── client.ts
│   │   │   │   │   ├── schema.ts
│   │   │   │   │   ├── types.ts
│   │   │   │   │   └── utils/
│   │   │   │   │       ├── json-api-error.ts
│   │   │   │   │       └── unwrap.ts
│   │   │   │   ├── auth/
│   │   │   │   │   └── types/
│   │   │   │   │       └── local-storage.keys.ts
│   │   │   │   ├── components/
│   │   │   │   │   ├── AudioPlayer/
│   │   │   │   │   │   ├── AudioPlayer.module.css
│   │   │   │   │   │   ├── AudioPlayer.stories.tsx
│   │   │   │   │   │   ├── AudioPlayer.tsx
│   │   │   │   │   │   └── index.ts
│   │   │   │   │   ├── Autocomplete/
│   │   │   │   │   │   ├── Autocomplete.module.css
│   │   │   │   │   │   ├── Autocomplete.stories.tsx
│   │   │   │   │   │   ├── Autocomplete.tsx
│   │   │   │   │   │   └── index.ts
│   │   │   │   │   ├── Avatar/
│   │   │   │   │   │   ├── Avatar.module.css
│   │   │   │   │   │   ├── Avatar.tsx
│   │   │   │   │   │   └── index.ts
│   │   │   │   │   ├── Button/
│   │   │   │   │   │   ├── Button.module.css
│   │   │   │   │   │   ├── Button.stories.tsx
│   │   │   │   │   │   ├── Button.tsx
│   │   │   │   │   │   └── index.ts
│   │   │   │   │   ├── Card/
│   │   │   │   │   │   ├── Card.module.css
│   │   │   │   │   │   ├── Card.stories.tsx
│   │   │   │   │   │   ├── Card.tsx
│   │   │   │   │   │   └── index.ts
│   │   │   │   │   ├── CoverImage/
│   │   │   │   │   │   ├── CoverImage.styles.module.scss
│   │   │   │   │   │   ├── CoverImage.tsx
│   │   │   │   │   │   └── index.ts
│   │   │   │   │   ├── Dialog/
│   │   │   │   │   │   ├── Dialog.module.css
│   │   │   │   │   │   ├── Dialog.stories.tsx
│   │   │   │   │   │   ├── Dialog.tsx
│   │   │   │   │   │   └── index.ts
│   │   │   │   │   ├── DropdownMenu/
│   │   │   │   │   │   ├── DropdownMenu.module.scss
│   │   │   │   │   │   ├── DropdownMenu.stories.tsx
│   │   │   │   │   │   ├── DropdownMenu.tsx
│   │   │   │   │   │   └── index.ts
│   │   │   │   │   ├── FormControlledTextField/
│   │   │   │   │   │   ├── FormControlledTextField.tsx
│   │   │   │   │   │   └── index.ts
│   │   │   │   │   ├── Hashtag/
│   │   │   │   │   │   ├── Tag.module.css
│   │   │   │   │   │   ├── Tag.stories.tsx
│   │   │   │   │   │   ├── Tag.tsx
│   │   │   │   │   │   └── index.ts
│   │   │   │   │   ├── IconButton/
│   │   │   │   │   │   ├── IconButton.module.css
│   │   │   │   │   │   ├── IconButton.stories.tsx
│   │   │   │   │   │   ├── IconButton.tsx
│   │   │   │   │   │   └── index.ts
│   │   │   │   │   ├── ImageCropper/
│   │   │   │   │   │   ├── ImageCropper.module.css
│   │   │   │   │   │   ├── ImageCropper.tsx
│   │   │   │   │   │   └── index.ts
│   │   │   │   │   ├── ImageUploader/
│   │   │   │   │   │   ├── ImageUploader.module.css
│   │   │   │   │   │   ├── ImageUploader.stories.tsx
│   │   │   │   │   │   ├── ImageUploader.tsx
│   │   │   │   │   │   └── index.ts
│   │   │   │   │   ├── LanguageSwitcher/
│   │   │   │   │   │   ├── LanguageSwitcher.tsx
│   │   │   │   │   │   └── index.ts
│   │   │   │   │   ├── Pagination/
│   │   │   │   │   │   ├── Pagination.module.css
│   │   │   │   │   │   ├── Pagination.stories.tsx
│   │   │   │   │   │   ├── Pagination.tsx
│   │   │   │   │   │   └── index.ts
│   │   │   │   │   ├── Progress/
│   │   │   │   │   │   ├── Progress.module.css
│   │   │   │   │   │   ├── Progress.stories.tsx
│   │   │   │   │   │   ├── Progress.tsx
│   │   │   │   │   │   └── index.ts
│   │   │   │   │   ├── ReactionButtons/
│   │   │   │   │   │   ├── ReactionButtons.module.css
│   │   │   │   │   │   ├── ReactionButtons.stories.tsx
│   │   │   │   │   │   ├── ReactionButtons.tsx
│   │   │   │   │   │   └── index.ts
│   │   │   │   │   ├── SearchField/
│   │   │   │   │   │   ├── SearchField.module.css
│   │   │   │   │   │   ├── SearchField.stories.tsx
│   │   │   │   │   │   ├── SearchField.tsx
│   │   │   │   │   │   └── index.ts
│   │   │   │   │   ├── Select/
│   │   │   │   │   │   ├── Select.module.css
│   │   │   │   │   │   ├── Select.stories.tsx
│   │   │   │   │   │   ├── Select.tsx
│   │   │   │   │   │   └── index.ts
│   │   │   │   │   ├── Skeleton/
│   │   │   │   │   │   ├── Skeleton.module.css
│   │   │   │   │   │   ├── Skeleton.tsx
│   │   │   │   │   │   └── index.ts
│   │   │   │   │   ├── SortSelect/
│   │   │   │   │   │   └── Select.tsx
│   │   │   │   │   ├── Spinner/
│   │   │   │   │   │   ├── Spinner.stories.tsx
│   │   │   │   │   │   ├── Spinner.tsx
│   │   │   │   │   │   ├── index.ts
│   │   │   │   │   │   └── spinner.module.css
│   │   │   │   │   ├── Table/
│   │   │   │   │   │   ├── Table.module.css
│   │   │   │   │   │   ├── Table.stories.tsx
│   │   │   │   │   │   ├── Table.tsx
│   │   │   │   │   │   └── index.ts
│   │   │   │   │   ├── Tabs/
│   │   │   │   │   │   ├── Tabs.module.css
│   │   │   │   │   │   ├── Tabs.stories.tsx
│   │   │   │   │   │   ├── Tabs.tsx
│   │   │   │   │   │   └── index.ts
│   │   │   │   │   ├── TagEditor/
│   │   │   │   │   │   ├── TagEditor.module.css
│   │   │   │   │   │   ├── TagEditor.stories.tsx
│   │   │   │   │   │   ├── TagEditor.tsx
│   │   │   │   │   │   └── index.ts
│   │   │   │   │   ├── TextField/
│   │   │   │   │   │   ├── TextField.module.css
│   │   │   │   │   │   ├── TextField.stories.tsx
│   │   │   │   │   │   ├── TextField.tsx
│   │   │   │   │   │   └── index.ts
│   │   │   │   │   ├── Textarea/
│   │   │   │   │   │   ├── Textarea.module.css
│   │   │   │   │   │   ├── Textarea.stories.tsx
│   │   │   │   │   │   ├── Textarea.tsx
│   │   │   │   │   │   └── index.ts
│   │   │   │   │   ├── Typography/
│   │   │   │   │   │   ├── Typography.module.css
│   │   │   │   │   │   ├── Typography.stories.tsx
│   │   │   │   │   │   ├── Typography.tsx
│   │   │   │   │   │   └── index.ts
│   │   │   │   │   └── index.ts
│   │   │   │   ├── config/
│   │   │   │   │   ├── config.ts
│   │   │   │   │   └── paths.ts
│   │   │   │   ├── featureFlags.ts
│   │   │   │   ├── hooks/
│   │   │   │   │   ├── debounceCallback/
│   │   │   │   │   │   ├── index.ts
│   │   │   │   │   │   ├── useDebounceCallback.ts
│   │   │   │   │   │   └── useDebounceCallback.types.ts
│   │   │   │   │   ├── debounceValue/
│   │   │   │   │   │   ├── index.ts
│   │   │   │   │   │   └── useDebounceValue.ts
│   │   │   │   │   ├── getId/
│   │   │   │   │   │   ├── index.ts
│   │   │   │   │   │   └── useGetId.ts
│   │   │   │   │   ├── index.ts
│   │   │   │   │   ├── throttleCallback/
│   │   │   │   │   │   ├── index.ts
│   │   │   │   │   │   ├── useThrottleCallback.tsx
│   │   │   │   │   │   └── useThrottleCallback.types.ts
│   │   │   │   │   ├── useCurrentPage.ts
│   │   │   │   │   ├── useDeletePlaylistAction.ts
│   │   │   │   │   ├── useEntityReactions.ts
│   │   │   │   │   ├── useHover.ts
│   │   │   │   │   ├── usePageBackgroundColor.ts
│   │   │   │   │   └── usePageSearchParams.ts
│   │   │   │   ├── icons/
│   │   │   │   │   ├── AddToPlaylistIcon.tsx
│   │   │   │   │   ├── ArrowBackIcon.tsx
│   │   │   │   │   ├── ArrowDownIcon.tsx
│   │   │   │   │   ├── CheckedIcon.tsx
│   │   │   │   │   ├── ClockIcon.tsx
│   │   │   │   │   ├── CreateIcon.tsx
│   │   │   │   │   ├── DeleteIcon.tsx
│   │   │   │   │   ├── DeleteTagIconButton.tsx
│   │   │   │   │   ├── DislikeIcon.tsx
│   │   │   │   │   ├── DownloadIcon.tsx
│   │   │   │   │   ├── EditIcon.tsx
│   │   │   │   │   ├── HomeIcon.tsx
│   │   │   │   │   ├── ImageUploadIcon.tsx
│   │   │   │   │   ├── KeyboardArrowLeftIcon.tsx
│   │   │   │   │   ├── KeyboardArrowRightIcon.tsx
│   │   │   │   │   ├── LanguageIcon.tsx
│   │   │   │   │   ├── LibraryIcon.tsx
│   │   │   │   │   ├── LikeIcon.tsx
│   │   │   │   │   ├── LikeIconFill.tsx
│   │   │   │   │   ├── LikeInSquareIcon.tsx
│   │   │   │   │   ├── LiveWaveIcon/
│   │   │   │   │   │   ├── LiveWaveIcon.module.css
│   │   │   │   │   │   ├── LiveWaveIcon.tsx
│   │   │   │   │   │   └── index.ts
│   │   │   │   │   ├── LogoutIcon.tsx
│   │   │   │   │   ├── MoreIcon.tsx
│   │   │   │   │   ├── PauseIcon.tsx
│   │   │   │   │   ├── PlayIcon.tsx
│   │   │   │   │   ├── PlaylistIcon.tsx
│   │   │   │   │   ├── PlusIcon.tsx
│   │   │   │   │   ├── ProfileIcon.tsx
│   │   │   │   │   ├── RepeatIcon.tsx
│   │   │   │   │   ├── SearchIcon.tsx
│   │   │   │   │   ├── ShuffleIcon.tsx
│   │   │   │   │   ├── SkipNextIcon.tsx
│   │   │   │   │   ├── SkipPreviousIcon.tsx
│   │   │   │   │   ├── TextIcon.tsx
│   │   │   │   │   ├── TrackIcon.tsx
│   │   │   │   │   ├── UncheckedIcon.tsx
│   │   │   │   │   ├── UploadIcon.tsx
│   │   │   │   │   ├── VolumeIcon.tsx
│   │   │   │   │   ├── VolumeMuteIcon.tsx
│   │   │   │   │   └── index.ts
│   │   │   │   ├── model/
│   │   │   │   │   └── ui-store.ts
│   │   │   │   ├── translations/
│   │   │   │   │   ├── i18nConfiguration.ts
│   │   │   │   │   └── languages/
│   │   │   │   │       ├── en.json
│   │   │   │   │       └── ru.json
│   │   │   │   ├── types/
│   │   │   │   │   ├── api-track.types.ts
│   │   │   │   │   └── strict.tsx
│   │   │   │   ├── ui/
│   │   │   │   │   ├── prerender-ready.tsx
│   │   │   │   │   └── utils/
│   │   │   │   │       └── query-error-handler-for-rhf-factory.ts
│   │   │   │   └── utils/
│   │   │   │       ├── authStorage.ts
│   │   │   │       ├── decode-file-from-base-64.ts
│   │   │   │       ├── format-created-date.ts
│   │   │   │       ├── get-artist-id.ts
│   │   │   │       ├── get-artist-name.ts
│   │   │   │       ├── get-artists-by-track.ts
│   │   │   │       ├── get-audio-url.ts
│   │   │   │       ├── get-cover-url.ts
│   │   │   │       ├── get-image-by-type.ts
│   │   │   │       ├── get-plural-key.ts
│   │   │   │       ├── get-russian-plural-form.ts
│   │   │   │       ├── get-user-initials.ts
│   │   │   │       ├── index.ts
│   │   │   │       ├── join-url.test.ts
│   │   │   │       ├── join-url.ts
│   │   │   │       ├── set-locale.ts
│   │   │   │       └── validators/
│   │   │   │           ├── getType.ts
│   │   │   │           ├── inNun.ts
│   │   │   │           ├── index.ts
│   │   │   │           ├── isArray.ts
│   │   │   │           ├── isFunction.ts
│   │   │   │           ├── isNotEmptyArray.ts
│   │   │   │           ├── isNull.ts
│   │   │   │           ├── isNumber.ts
│   │   │   │           ├── isObject.ts
│   │   │   │           ├── isString.ts
│   │   │   │           ├── isUndefined.ts
│   │   │   │           ├── isValid.ts
│   │   │   │           ├── isValidNumber.ts
│   │   │   │           ├── isValidObject.ts
│   │   │   │           └── isValidString.ts
│   │   │   └── widgets/
│   │   │       └── Player/
│   │   │           ├── Player.module.css
│   │   │           ├── Player.tsx
│   │   │           └── index.ts
│   │   ├── stylelint.config.js
│   │   ├── tsconfig.app.json
│   │   ├── tsconfig.json
│   │   ├── tsconfig.node.json
│   │   └── vite.config.ts
│   └── ui-vanilla/
│       ├── .gitignore
│       ├── .storybook/
│       │   ├── main.ts
│       │   └── preview.tsx
│       ├── README.md
│       ├── eslint.config.js
│       ├── index.html
│       ├── package.json
│       ├── src/
│       │   ├── app/
│       │   │   ├── App.tsx
│       │   │   └── routing/
│       │   │       ├── Routing.tsx
│       │   │       └── index.ts
│       │   ├── features/
│       │   │   ├── artists/
│       │   │   │   ├── api/
│       │   │   │   │   ├── artists-api.ts
│       │   │   │   │   └── index.ts
│       │   │   │   ├── index.ts
│       │   │   │   └── ui/
│       │   │   │       └── ArtistCard/
│       │   │   │           ├── ArtistCard.module.css
│       │   │   │           ├── ArtistCard.stories.tsx
│       │   │   │           ├── ArtistCard.tsx
│       │   │   │           └── index.ts
│       │   │   ├── auth/
│       │   │   │   ├── index.ts
│       │   │   │   └── ui/
│       │   │   │       ├── LoginButtonAndModal/
│       │   │   │       │   ├── LoginButtonAndModal.module.css
│       │   │   │       │   ├── LoginButtonAndModal.tsx
│       │   │   │       │   └── index.ts
│       │   │   │       ├── ProfileDropdownMenu/
│       │   │   │       │   ├── ProfileDropdownMenu.module.css
│       │   │   │       │   ├── ProfileDropdownMenu.stories.tsx
│       │   │   │       │   ├── ProfileDropdownMenu.tsx
│       │   │   │       │   └── index.ts
│       │   │   │       └── index.ts
│       │   │   ├── playlists/
│       │   │   │   ├── api/
│       │   │   │   │   ├── index.ts
│       │   │   │   │   └── playlistsApi.ts
│       │   │   │   ├── index.ts
│       │   │   │   └── ui/
│       │   │   │       ├── CreatePlaylistModal/
│       │   │   │       │   ├── CreatePlaylistModal.module.css
│       │   │   │       │   ├── CreatePlaylistModal.tsx
│       │   │   │       │   └── index.ts
│       │   │   │       ├── PlaylistCard/
│       │   │   │       │   ├── PlaylistCard.module.css
│       │   │   │       │   ├── PlaylistCard.stories.tsx
│       │   │   │       │   ├── PlaylistCard.tsx
│       │   │   │       │   └── index.ts
│       │   │   │       ├── PlaylistOverview/
│       │   │   │       │   ├── PlaylistOverview.module.css
│       │   │   │       │   ├── PlaylistOverview.stories.tsx
│       │   │   │       │   ├── PlaylistOverview.tsx
│       │   │   │       │   └── index.ts
│       │   │   │       └── index.ts
│       │   │   ├── tags/
│       │   │   │   ├── api/
│       │   │   │   │   ├── index.ts
│       │   │   │   │   └── tags-api.ts
│       │   │   │   ├── index.ts
│       │   │   │   └── ui/
│       │   │   │       ├── TagsList/
│       │   │   │       │   ├── TagsList.module.css
│       │   │   │       │   ├── TagsList.stories.tsx
│       │   │   │       │   ├── TagsList.tsx
│       │   │   │       │   └── index.ts
│       │   │   │       └── index.ts
│       │   │   └── tracks/
│       │   │       ├── api/
│       │   │       │   ├── index.ts
│       │   │       │   ├── tracksApi.ts
│       │   │       │   └── types.ts
│       │   │       ├── index.ts
│       │   │       └── ui/
│       │   │           ├── TrackCard/
│       │   │           │   ├── TrackCard.module.css
│       │   │           │   ├── TrackCard.stories.tsx
│       │   │           │   ├── TrackCard.tsx
│       │   │           │   └── index.ts
│       │   │           ├── TrackInfoCell/
│       │   │           │   ├── TrackInfoCell.module.css
│       │   │           │   ├── TrackInfoCell.tsx
│       │   │           │   └── index.ts
│       │   │           ├── TrackOverview/
│       │   │           │   ├── TrackOverview.module.css
│       │   │           │   ├── TrackOverview.stories.tsx
│       │   │           │   ├── TrackOverview.tsx
│       │   │           │   └── index.ts
│       │   │           ├── TrackRow/
│       │   │           │   ├── TrackRow.module.css
│       │   │           │   └── TrackRow.tsx
│       │   │           ├── TracksTable/
│       │   │           │   ├── TrackTable.stories.tsx
│       │   │           │   ├── TracksTable.tsx
│       │   │           │   └── index.ts
│       │   │           └── index.ts
│       │   ├── layout/
│       │   │   ├── Header/
│       │   │   │   ├── Header.module.css
│       │   │   │   ├── Header.tsx
│       │   │   │   └── index.ts
│       │   │   ├── Layout.module.css
│       │   │   ├── Layout.tsx
│       │   │   ├── Sidebar/
│       │   │   │   ├── MenuLinks/
│       │   │   │   │   ├── MenuLinks.module.css
│       │   │   │   │   ├── MenuLinks.tsx
│       │   │   │   │   └── index.ts
│       │   │   │   ├── Sidebar.module.css
│       │   │   │   ├── Sidebar.tsx
│       │   │   │   └── index.ts
│       │   │   └── index.ts
│       │   ├── main.tsx
│       │   ├── pages/
│       │   │   ├── MainPage/
│       │   │   │   ├── MainPage.module.css
│       │   │   │   ├── MainPage.tsx
│       │   │   │   └── index.ts
│       │   │   ├── PlaylistPage/
│       │   │   │   ├── PlaylistPage.module.css
│       │   │   │   ├── PlaylistPage.tsx
│       │   │   │   ├── index.ts
│       │   │   │   └── ui/
│       │   │   │       └── ControlPanel/
│       │   │   │           ├── ControlPanel.module.css
│       │   │   │           ├── ControlPanel.tsx
│       │   │   │           └── index.ts
│       │   │   ├── PlaylistsPage/
│       │   │   │   ├── PlaylistsPage.module.css
│       │   │   │   ├── PlaylistsPage.tsx
│       │   │   │   └── index.ts
│       │   │   ├── TrackPage/
│       │   │   │   ├── TrackPage.module.css
│       │   │   │   ├── TrackPage.tsx
│       │   │   │   ├── index.ts
│       │   │   │   └── ui/
│       │   │   │       └── ControlPanel/
│       │   │   │           ├── ControlPanel.module.css
│       │   │   │           ├── ControlPanel.tsx
│       │   │   │           └── index.ts
│       │   │   ├── TracksPage/
│       │   │   │   ├── TracksPage.module.css
│       │   │   │   ├── TracksPage.tsx
│       │   │   │   └── index.ts
│       │   │   ├── UserPage/
│       │   │   │   ├── UserPage.module.css
│       │   │   │   ├── UserPage.tsx
│       │   │   │   ├── index.ts
│       │   │   │   └── ui/
│       │   │   │       ├── UserInfo/
│       │   │   │       │   ├── UserInfo.module.css
│       │   │   │       │   ├── UserInfo.tsx
│       │   │   │       │   └── index.ts
│       │   │   │       ├── UserTabs/
│       │   │   │       │   ├── LikedTracksTab/
│       │   │   │       │   │   ├── LikedTracksTab.module.css
│       │   │   │       │   │   ├── LikedTracksTab.tsx
│       │   │   │       │   │   └── index.ts
│       │   │   │       │   ├── MyLikedPlaylistsTab/
│       │   │   │       │   │   ├── MyLikedPlaylistsTab.tsx
│       │   │   │       │   │   └── index.ts
│       │   │   │       │   ├── PlaylistsTab/
│       │   │   │       │   │   ├── PlaylistsTab.module.css
│       │   │   │       │   │   ├── PlaylistsTab.tsx
│       │   │   │       │   │   └── index.ts
│       │   │   │       │   ├── TracksTab/
│       │   │   │       │   │   ├── TracksTab.module.css
│       │   │   │       │   │   ├── TracksTab.tsx
│       │   │   │       │   │   └── index.ts
│       │   │   │       │   ├── UserTabs.tsx
│       │   │   │       │   └── index.ts
│       │   │   │       └── index.ts
│       │   │   ├── common/
│       │   │   │   ├── ContentList/
│       │   │   │   │   ├── ContentList.module.css
│       │   │   │   │   ├── ContentList.tsx
│       │   │   │   │   └── index.ts
│       │   │   │   ├── PageWrapper/
│       │   │   │   │   ├── PageWrapper.module.css
│       │   │   │   │   ├── PageWrapper.tsx
│       │   │   │   │   └── index.ts
│       │   │   │   ├── SearchTextField/
│       │   │   │   │   ├── SearchTextField.tsx
│       │   │   │   │   └── index.ts
│       │   │   │   ├── SortSelect/
│       │   │   │   │   ├── SortSelect.module.css
│       │   │   │   │   ├── SortSelect.tsx
│       │   │   │   │   └── index.ts
│       │   │   │   └── index.ts
│       │   │   └── index.ts
│       │   ├── shared/
│       │   │   ├── components/
│       │   │   │   ├── AudioPlayer/
│       │   │   │   │   ├── AudioPlayer.module.css
│       │   │   │   │   ├── AudioPlayer.stories.tsx
│       │   │   │   │   ├── AudioPlayer.tsx
│       │   │   │   │   └── index.ts
│       │   │   │   ├── Autocomplete/
│       │   │   │   │   ├── Autocomplete.module.css
│       │   │   │   │   ├── Autocomplete.stories.tsx
│       │   │   │   │   ├── Autocomplete.tsx
│       │   │   │   │   └── index.ts
│       │   │   │   ├── Button/
│       │   │   │   │   ├── Button.module.css
│       │   │   │   │   ├── Button.stories.tsx
│       │   │   │   │   ├── Button.tsx
│       │   │   │   │   └── index.ts
│       │   │   │   ├── Card/
│       │   │   │   │   ├── Card.module.css
│       │   │   │   │   ├── Card.stories.tsx
│       │   │   │   │   ├── Card.tsx
│       │   │   │   │   └── index.ts
│       │   │   │   ├── Dialog/
│       │   │   │   │   ├── Dialog.module.css
│       │   │   │   │   ├── Dialog.stories.tsx
│       │   │   │   │   ├── Dialog.tsx
│       │   │   │   │   └── index.ts
│       │   │   │   ├── DropdownMenu/
│       │   │   │   │   ├── DropdownMenu.module.css
│       │   │   │   │   ├── DropdownMenu.stories.tsx
│       │   │   │   │   ├── DropdownMenu.tsx
│       │   │   │   │   └── index.ts
│       │   │   │   ├── Hashtag/
│       │   │   │   │   ├── Tag.module.css
│       │   │   │   │   ├── Tag.stories.tsx
│       │   │   │   │   ├── Tag.tsx
│       │   │   │   │   └── index.ts
│       │   │   │   ├── IconButton/
│       │   │   │   │   ├── IconButton.module.css
│       │   │   │   │   ├── IconButton.stories.tsx
│       │   │   │   │   ├── IconButton.tsx
│       │   │   │   │   └── index.ts
│       │   │   │   ├── ImageUploader/
│       │   │   │   │   ├── ImageUploader.module.css
│       │   │   │   │   ├── ImageUploader.stories.tsx
│       │   │   │   │   ├── ImageUploader.tsx
│       │   │   │   │   └── index.ts
│       │   │   │   ├── Pagination/
│       │   │   │   │   ├── Pagination.module.css
│       │   │   │   │   ├── Pagination.stories.tsx
│       │   │   │   │   ├── Pagination.tsx
│       │   │   │   │   └── index.ts
│       │   │   │   ├── Progress/
│       │   │   │   │   ├── Progress.module.css
│       │   │   │   │   ├── Progress.stories.tsx
│       │   │   │   │   ├── Progress.tsx
│       │   │   │   │   └── index.ts
│       │   │   │   ├── ReactionButtons/
│       │   │   │   │   ├── ReactionButtons.module.css
│       │   │   │   │   ├── ReactionButtons.stories.tsx
│       │   │   │   │   ├── ReactionButtons.tsx
│       │   │   │   │   └── index.ts
│       │   │   │   ├── SearchField/
│       │   │   │   │   ├── SearchField.module.css
│       │   │   │   │   ├── SearchField.stories.tsx
│       │   │   │   │   ├── SearchField.tsx
│       │   │   │   │   └── index.ts
│       │   │   │   ├── Select/
│       │   │   │   │   ├── Select.module.css
│       │   │   │   │   ├── Select.stories.tsx
│       │   │   │   │   ├── Select.tsx
│       │   │   │   │   └── index.ts
│       │   │   │   ├── SortSelect/
│       │   │   │   │   └── Select.tsx
│       │   │   │   ├── Table/
│       │   │   │   │   ├── Table.module.css
│       │   │   │   │   ├── Table.stories.tsx
│       │   │   │   │   ├── Table.tsx
│       │   │   │   │   └── index.ts
│       │   │   │   ├── Tabs/
│       │   │   │   │   ├── Tabs.module.css
│       │   │   │   │   ├── Tabs.stories.tsx
│       │   │   │   │   ├── Tabs.tsx
│       │   │   │   │   └── index.ts
│       │   │   │   ├── TagEditor/
│       │   │   │   │   ├── TagEditor.module.css
│       │   │   │   │   ├── TagEditor.stories.tsx
│       │   │   │   │   ├── TagEditor.tsx
│       │   │   │   │   └── index.ts
│       │   │   │   ├── TextField/
│       │   │   │   │   ├── TextField.module.css
│       │   │   │   │   ├── TextField.stories.tsx
│       │   │   │   │   ├── TextField.tsx
│       │   │   │   │   └── index.ts
│       │   │   │   ├── Textarea/
│       │   │   │   │   ├── Textarea.module.css
│       │   │   │   │   ├── Textarea.stories.tsx
│       │   │   │   │   ├── Textarea.tsx
│       │   │   │   │   └── index.ts
│       │   │   │   ├── Typography/
│       │   │   │   │   ├── Typography.module.css
│       │   │   │   │   ├── Typography.stories.tsx
│       │   │   │   │   ├── Typography.tsx
│       │   │   │   │   └── index.ts
│       │   │   │   └── index.ts
│       │   │   ├── hooks/
│       │   │   │   ├── index.ts
│       │   │   │   └── useGetId.ts
│       │   │   └── icons/
│       │   │       ├── AddToPlaylistIcon.tsx
│       │   │       ├── ArrowDownIcon.tsx
│       │   │       ├── ClockIcon.tsx
│       │   │       ├── CreateIcon.tsx
│       │   │       ├── DeleteIcon.tsx
│       │   │       ├── DislikeIcon.tsx
│       │   │       ├── DownloadIcon.tsx
│       │   │       ├── EditIcon.tsx
│       │   │       ├── HomeIcon.tsx
│       │   │       ├── ImageUploadIcon.tsx
│       │   │       ├── KeyboardArrowLeftIcon.tsx
│       │   │       ├── KeyboardArrowRightIcon.tsx
│       │   │       ├── LibraryIcon.tsx
│       │   │       ├── LikeIcon.tsx
│       │   │       ├── LikeIconFill.tsx
│       │   │       ├── LikeInSquareIcon.tsx
│       │   │       ├── LiveWaveIcon/
│       │   │       │   ├── LiveWaveIcon.module.css
│       │   │       │   ├── LiveWaveIcon.tsx
│       │   │       │   └── index.ts
│       │   │       ├── LogoutIcon.tsx
│       │   │       ├── MoreIcon.tsx
│       │   │       ├── PauseIcon.tsx
│       │   │       ├── PlayIcon.tsx
│       │   │       ├── PlaylistIcon.tsx
│       │   │       ├── PlusIcon.tsx
│       │   │       ├── ProfileIcon.tsx
│       │   │       ├── RepeatIcon.tsx
│       │   │       ├── SearchIcon.tsx
│       │   │       ├── ShuffleIcon.tsx
│       │   │       ├── SkipNextIcon.tsx
│       │   │       ├── SkipPreviousIcon.tsx
│       │   │       ├── TextIcon.tsx
│       │   │       ├── TrackIcon.tsx
│       │   │       ├── UploadIcon.tsx
│       │   │       ├── VolumeIcon.tsx
│       │   │       ├── VolumeMuteIcon.tsx
│       │   │       └── index.ts
│       │   ├── styles/
│       │   │   ├── fonts.css
│       │   │   ├── global.css
│       │   │   ├── reset.css
│       │   │   └── variables.css
│       │   ├── vite-env.d.ts
│       │   └── widgets/
│       │       └── Player/
│       │           ├── Player.module.css
│       │           ├── Player.tsx
│       │           └── index.ts
│       ├── stylelint.config.js
│       ├── tsconfig.app.json
│       ├── tsconfig.json
│       ├── tsconfig.node.json
│       └── vite.config.ts
├── architecture/
│   └── microfrontends/
│       ├── player/
│       │   ├── .gitignore
│       │   ├── README.md
│       │   ├── eslint.config.js
│       │   ├── index.html
│       │   ├── package.json
│       │   ├── src/
│       │   │   ├── App.css
│       │   │   ├── App.tsx
│       │   │   ├── index.css
│       │   │   └── main.tsx
│       │   ├── tsconfig.app.json
│       │   ├── tsconfig.json
│       │   ├── tsconfig.node.json
│       │   ├── vite.config.readme.md
│       │   └── vite.config.ts
│       └── root/
│           ├── .gitignore
│           ├── README.md
│           ├── eslint.config.js
│           ├── index.html
│           ├── package.json
│           ├── src/
│           │   ├── App.css
│           │   ├── App.tsx
│           │   ├── index.css
│           │   └── main.tsx
│           ├── tsconfig.app.json
│           ├── tsconfig.json
│           ├── tsconfig.node.json
│           └── vite.config.ts
├── content-thoughts/
│   └── search-input/
│       └── info.md
├── docs/
│   ├── feature-comparison.md
│   └── todos-features.md
├── eslint.config.js
├── experiment-apps/
│   ├── musicfun-tanstack-query-orval-small-example/
│   │   ├── .gitignore
│   │   ├── README.md
│   │   ├── eslint.config.js
│   │   ├── index.html
│   │   ├── orval.config.cjs
│   │   ├── package.json
│   │   ├── src/
│   │   │   ├── app/
│   │   │   │   ├── entrypoint/
│   │   │   │   │   └── main.tsx
│   │   │   │   ├── layouts/
│   │   │   │   │   ├── root-layout.module.css
│   │   │   │   │   └── root-layout.tsx
│   │   │   │   ├── providers/
│   │   │   │   │   └── web-socket-provider.tsx
│   │   │   │   ├── query-client/
│   │   │   │   │   └── query-client.tsx
│   │   │   │   ├── routes/
│   │   │   │   │   ├── __root.tsx
│   │   │   │   │   ├── index.tsx
│   │   │   │   │   ├── my-playlists.tsx
│   │   │   │   │   ├── oauth/
│   │   │   │   │   │   └── callback.tsx
│   │   │   │   │   └── playlists-with-filters.tsx
│   │   │   │   └── styles/
│   │   │   │       ├── index.css
│   │   │   │       └── reset.css
│   │   │   ├── features/
│   │   │   │   ├── auth/
│   │   │   │   │   ├── api/
│   │   │   │   │   │   ├── auth-api.types.ts
│   │   │   │   │   │   ├── use-login.mutation.ts
│   │   │   │   │   │   ├── use-logout.mutation.ts
│   │   │   │   │   │   └── use-me.query.ts
│   │   │   │   │   ├── index.tsx
│   │   │   │   │   └── ui/
│   │   │   │   │       ├── account-bar.module.css
│   │   │   │   │       ├── account-bar.tsx
│   │   │   │   │       ├── current-user/
│   │   │   │   │       │   └── current-user.tsx
│   │   │   │   │       ├── login-button/
│   │   │   │   │       │   ├── login-button.tsx
│   │   │   │   │       │   └── use-login.tsx
│   │   │   │   │       └── logout-button/
│   │   │   │   │           ├── logout-button.tsx
│   │   │   │   │           └── use-logout.ts
│   │   │   │   └── playlists/
│   │   │   │       ├── add-playlist-form/
│   │   │   │       │   ├── add-playlist-form.module.css
│   │   │   │       │   └── add-playlist-form.tsx
│   │   │   │       ├── api/
│   │   │   │       │   └── use-playlists-query.tsx
│   │   │   │       ├── edit-playlist-form/
│   │   │   │       │   └── edit-playlist-form.tsx
│   │   │   │       ├── list/
│   │   │   │       │   ├── paginated-playlists.module.css
│   │   │   │       │   ├── paginated-playlists.tsx
│   │   │   │       │   └── playlists.tsx
│   │   │   │       └── playlist-cover/
│   │   │   │           ├── playlist-cover.module.css
│   │   │   │           └── playlist-cover.tsx
│   │   │   ├── pages/
│   │   │   │   ├── auth/
│   │   │   │   │   ├── index.tsx
│   │   │   │   │   └── ui/
│   │   │   │   │       └── oauth-callback-page.tsx
│   │   │   │   └── playlists/
│   │   │   │       └── ui/
│   │   │   │           ├── my-playlists/
│   │   │   │           │   ├── my-playlists-page.module.css
│   │   │   │           │   └── my-playlists-page.tsx
│   │   │   │           └── playlists-with-filters-page.tsx
│   │   │   ├── shared/
│   │   │   │   ├── api/
│   │   │   │   │   ├── client.ts
│   │   │   │   │   ├── index.ts
│   │   │   │   │   ├── json-api-error.ts
│   │   │   │   │   ├── orval/
│   │   │   │   │   │   ├── artists/
│   │   │   │   │   │   │   └── artists.ts
│   │   │   │   │   │   ├── authentication/
│   │   │   │   │   │   │   └── authentication.ts
│   │   │   │   │   │   ├── custom-instance.ts
│   │   │   │   │   │   ├── musicfun.schemas.ts
│   │   │   │   │   │   ├── musicfun.ts
│   │   │   │   │   │   ├── playlists-owner/
│   │   │   │   │   │   │   └── playlists-owner.ts
│   │   │   │   │   │   ├── playlists-public/
│   │   │   │   │   │   │   └── playlists-public.ts
│   │   │   │   │   │   ├── tags/
│   │   │   │   │   │   │   └── tags.ts
│   │   │   │   │   │   ├── tracks-owner/
│   │   │   │   │   │   │   └── tracks-owner.ts
│   │   │   │   │   │   └── tracks-public/
│   │   │   │   │   │       └── tracks-public.ts
│   │   │   │   │   ├── query-error-handler-for-rhf-factory.ts
│   │   │   │   │   ├── request-wrapper.ts
│   │   │   │   │   ├── schema.ts
│   │   │   │   │   └── socket.ts
│   │   │   │   ├── config/
│   │   │   │   │   └── api.config.ts
│   │   │   │   ├── db/
│   │   │   │   │   └── localstorage-keys.ts
│   │   │   │   ├── routes/
│   │   │   │   │   └── routes.ts
│   │   │   │   └── ui/
│   │   │   │       ├── header/
│   │   │   │       │   ├── header.component.tsx
│   │   │   │       │   └── header.module.css
│   │   │   │       └── pagination/
│   │   │   │           ├── pagination-nav/
│   │   │   │           │   ├── pagination-nav.module.css
│   │   │   │           │   └── pagination-nav.tsx
│   │   │   │           ├── pagination.module.css
│   │   │   │           ├── pagination.tsx
│   │   │   │           └── utils/
│   │   │   │               └── get-pagination-pages.ts
│   │   │   └── vite-env.d.ts
│   │   ├── tsconfig.app.json
│   │   ├── tsconfig.json
│   │   ├── tsconfig.node.json
│   │   ├── tsr.config.json
│   │   └── vite.config.ts
│   ├── musicfun-tanstack-query-small-example/
│   │   ├── .gitignore
│   │   ├── README.md
│   │   ├── eslint.config.js
│   │   ├── index.html
│   │   ├── package.json
│   │   ├── src/
│   │   │   ├── app/
│   │   │   │   ├── entrypoint/
│   │   │   │   │   └── main.tsx
│   │   │   │   ├── layouts/
│   │   │   │   │   ├── root-layout.module.css
│   │   │   │   │   └── root-layout.tsx
│   │   │   │   ├── providers/
│   │   │   │   │   └── web-socket-provider.tsx
│   │   │   │   ├── query-client/
│   │   │   │   │   └── query-client.tsx
│   │   │   │   ├── routes/
│   │   │   │   │   ├── __root.tsx
│   │   │   │   │   ├── index.tsx
│   │   │   │   │   ├── my-playlists.tsx
│   │   │   │   │   ├── oauth/
│   │   │   │   │   │   └── callback.tsx
│   │   │   │   │   └── playlists-with-filters.tsx
│   │   │   │   └── styles/
│   │   │   │       ├── index.css
│   │   │   │       └── reset.css
│   │   │   ├── features/
│   │   │   │   ├── auth/
│   │   │   │   │   ├── api/
│   │   │   │   │   │   ├── auth-api.types.ts
│   │   │   │   │   │   ├── use-login.mutation.ts
│   │   │   │   │   │   ├── use-logout.mutation.ts
│   │   │   │   │   │   └── use-me.query.ts
│   │   │   │   │   ├── index.tsx
│   │   │   │   │   └── ui/
│   │   │   │   │       ├── account-bar.module.css
│   │   │   │   │       ├── account-bar.tsx
│   │   │   │   │       ├── current-user/
│   │   │   │   │       │   └── current-user.tsx
│   │   │   │   │       ├── login-button/
│   │   │   │   │       │   ├── login-button.tsx
│   │   │   │   │       │   └── use-login.tsx
│   │   │   │   │       └── logout-button/
│   │   │   │   │           ├── logout-button.tsx
│   │   │   │   │           └── use-logout.ts
│   │   │   │   └── playlists/
│   │   │   │       ├── add-playlist-form/
│   │   │   │       │   ├── add-playlist-form.module.css
│   │   │   │       │   └── add-playlist-form.tsx
│   │   │   │       ├── api/
│   │   │   │       │   └── use-playlists-query.tsx
│   │   │   │       ├── edit-playlist-form/
│   │   │   │       │   └── edit-playlist-form.tsx
│   │   │   │       ├── list/
│   │   │   │       │   ├── paginated-playlists.module.css
│   │   │   │       │   ├── paginated-playlists.tsx
│   │   │   │       │   └── playlists.tsx
│   │   │   │       └── playlist-cover/
│   │   │   │           ├── playlist-cover.module.css
│   │   │   │           └── playlist-cover.tsx
│   │   │   ├── pages/
│   │   │   │   ├── auth/
│   │   │   │   │   ├── index.tsx
│   │   │   │   │   └── ui/
│   │   │   │   │       └── oauth-callback-page.tsx
│   │   │   │   └── playlists/
│   │   │   │       └── ui/
│   │   │   │           ├── my-playlists/
│   │   │   │           │   ├── my-playlists-page.module.css
│   │   │   │           │   └── my-playlists-page.tsx
│   │   │   │           └── playlists-with-filters-page.tsx
│   │   │   ├── shared/
│   │   │   │   ├── api/
│   │   │   │   │   ├── client.ts
│   │   │   │   │   ├── index.ts
│   │   │   │   │   ├── json-api-error.ts
│   │   │   │   │   ├── query-error-handler-for-rhf-factory.ts
│   │   │   │   │   ├── request-wrapper.ts
│   │   │   │   │   ├── schema.ts
│   │   │   │   │   └── socket.ts
│   │   │   │   ├── config/
│   │   │   │   │   └── api.config.ts
│   │   │   │   ├── db/
│   │   │   │   │   └── localstorage-keys.ts
│   │   │   │   ├── routes/
│   │   │   │   │   └── routes.ts
│   │   │   │   └── ui/
│   │   │   │       ├── header/
│   │   │   │       │   ├── header.component.tsx
│   │   │   │       │   └── header.module.css
│   │   │   │       └── pagination/
│   │   │   │           ├── pagination-nav/
│   │   │   │           │   ├── pagination-nav.module.css
│   │   │   │           │   └── pagination-nav.tsx
│   │   │   │           ├── pagination.module.css
│   │   │   │           ├── pagination.tsx
│   │   │   │           └── utils/
│   │   │   │               └── get-pagination-pages.ts
│   │   │   └── vite-env.d.ts
│   │   ├── tsconfig.app.json
│   │   ├── tsconfig.json
│   │   ├── tsconfig.node.json
│   │   ├── tsr.config.json
│   │   └── vite.config.ts
│   └── trelly-rtk/
│       ├── .gitignore
│       ├── .prettierrc
│       ├── README.md
│       ├── index.html
│       ├── openapi-config.js
│       ├── package.json
│       ├── src/
│       │   ├── app/
│       │   │   ├── api/
│       │   │   │   ├── baseApi.ts
│       │   │   │   ├── baseQuery.ts
│       │   │   │   └── baseQueryWithReauth.ts
│       │   │   ├── model/
│       │   │   │   ├── app-slice.ts
│       │   │   │   └── store.ts
│       │   │   └── ui/
│       │   │       ├── App.module.css
│       │   │       ├── App.tsx
│       │   │       └── Main.tsx
│       │   ├── common/
│       │   │   ├── actions/
│       │   │   │   ├── actions.ts
│       │   │   │   └── index.ts
│       │   │   ├── components/
│       │   │   │   ├── CreateItemForm/
│       │   │   │   │   └── CreateItemForm.tsx
│       │   │   │   ├── EditableSpan/
│       │   │   │   │   └── EditableSpan.tsx
│       │   │   │   ├── ErrorSnackbar/
│       │   │   │   │   └── ErrorSnackbar.tsx
│       │   │   │   ├── Header/
│       │   │   │   │   └── Header.tsx
│       │   │   │   ├── NavButton/
│       │   │   │   │   └── NavButton.ts
│       │   │   │   ├── PageNotFound/
│       │   │   │   │   ├── PageNotFound.module.css
│       │   │   │   │   └── PageNotFound.tsx
│       │   │   │   ├── ProtectedRoute/
│       │   │   │   │   └── ProtectedRoute.tsx
│       │   │   │   └── index.ts
│       │   │   ├── constants/
│       │   │   │   ├── constants.ts
│       │   │   │   └── index.ts
│       │   │   ├── enums/
│       │   │   │   ├── enums.ts
│       │   │   │   └── index.ts
│       │   │   ├── hooks/
│       │   │   │   ├── index.ts
│       │   │   │   ├── useAppDispatch.ts
│       │   │   │   └── useAppSelector.ts
│       │   │   ├── instance/
│       │   │   │   ├── index.ts
│       │   │   │   └── instance.ts
│       │   │   ├── routing/
│       │   │   │   ├── Routing.tsx
│       │   │   │   └── index.ts
│       │   │   ├── styles/
│       │   │   │   ├── container.styles.ts
│       │   │   │   └── index.ts
│       │   │   ├── theme/
│       │   │   │   ├── index.ts
│       │   │   │   └── theme.ts
│       │   │   ├── types/
│       │   │   │   ├── index.ts
│       │   │   │   └── types.ts
│       │   │   └── utils/
│       │   │       ├── createAppSlice.ts
│       │   │       ├── handleError.ts
│       │   │       ├── index.ts
│       │   │       ├── isErrorWithMessage.ts
│       │   │       └── isTokens.ts
│       │   ├── features/
│       │   │   ├── auth/
│       │   │   │   ├── api/
│       │   │   │   │   ├── authApi.ts
│       │   │   │   │   └── authApi.types.ts
│       │   │   │   ├── lib/
│       │   │   │   │   └── schemas/
│       │   │   │   │       ├── index.ts
│       │   │   │   │       └── loginSchema.ts
│       │   │   │   └── ui/
│       │   │   │       ├── Login/
│       │   │   │       │   ├── Login.module.css
│       │   │   │       │   └── Login.tsx
│       │   │   │       ├── OAuthCallback/
│       │   │   │       │   └── OAuthCallback.tsx
│       │   │   │       └── UserBlock/
│       │   │   │           └── UserBlock.tsx
│       │   │   ├── boards/
│       │   │   │   ├── api/
│       │   │   │   │   ├── boardsApi.ts
│       │   │   │   │   └── boardsApi.types.ts
│       │   │   │   ├── lib/
│       │   │   │   │   └── utils/
│       │   │   │   │       ├── createTaskModel.ts
│       │   │   │   │       └── index.ts
│       │   │   │   └── ui/
│       │   │   │       └── Boards/
│       │   │   │           ├── BoardItem/
│       │   │   │           │   ├── BoardItem.tsx
│       │   │   │           │   ├── BoardTitle/
│       │   │   │           │   │   ├── BoardTitle.module.css
│       │   │   │           │   │   └── BoardTitle.tsx
│       │   │   │           │   └── FilterButtons/
│       │   │   │           │       └── FilterButtons.tsx
│       │   │   │           ├── BoardSkeleton/
│       │   │   │           │   ├── BoardSkeleton.module.css
│       │   │   │           │   └── BoardSkeleton.tsx
│       │   │   │           └── Boards.tsx
│       │   │   └── tasks/
│       │   │       ├── api/
│       │   │       │   ├── tasksApi.ts
│       │   │       │   └── tasksApi.types.ts
│       │   │       └── ui/
│       │   │           └── Tasks/
│       │   │               ├── TaskItem/
│       │   │               │   ├── TaskItem.styles.ts
│       │   │               │   └── TaskItem.tsx
│       │   │               ├── Tasks.tsx
│       │   │               ├── TasksPagination/
│       │   │               │   ├── TasksPagination.module.css
│       │   │               │   └── TasksPagination.tsx
│       │   │               └── TasksSkeleton/
│       │   │                   └── TasksSkeleton.tsx
│       │   ├── index.css
│       │   ├── main.tsx
│       │   └── vite-env.d.ts
│       ├── tsconfig.app.json
│       ├── tsconfig.json
│       ├── tsconfig.node.json
│       └── vite.config.ts
├── package.json
├── packages/
│   └── musicfun-api-sdk/
│       ├── package.json
│       ├── src/
│       │   ├── api/
│       │   │   ├── artists/
│       │   │   │   ├── artistsApi.ts
│       │   │   │   └── artistsApi.types.ts
│       │   │   ├── auth/
│       │   │   │   ├── authApi.ts
│       │   │   │   └── authApi.types.ts
│       │   │   ├── playlists/
│       │   │   │   ├── playlistsApi.ts
│       │   │   │   └── playlistsApi.types.ts
│       │   │   ├── tags/
│       │   │   │   ├── tagsApi.ts
│       │   │   │   └── tagsApi.types.ts
│       │   │   └── tracks/
│       │   │       ├── tracksApi.ts
│       │   │       └── tracksApi.types.ts
│       │   ├── common/
│       │   │   ├── apiEntities/
│       │   │   │   └── apiEntities.ts
│       │   │   ├── instance/
│       │   │   │   └── instance.ts
│       │   │   ├── types/
│       │   │   │   ├── common.types.ts
│       │   │   │   ├── enums.ts
│       │   │   │   └── playlists-tracks.types.ts
│       │   │   └── utils/
│       │   │       └── urlHelper.ts
│       │   ├── index.ts
│       │   └── v2/
│       │       └── request.ts
│       └── tsconfig.json
├── public/
│   ├── 404.html
│   └── index.html
├── type-comparison-examples.md
└── youtube/
    ├── markup/
    │   ├── .gitignore
    │   ├── README.md
    │   ├── eslint.config.js
    │   ├── index.html
    │   ├── package.json
    │   ├── tsconfig.app.json
    │   ├── tsconfig.json
    │   ├── tsconfig.node.json
    │   └── vite.config.ts
    ├── rtk-query/
    │   └── lesson1/
    │       ├── .gitignore
    │       ├── .prettierrc
    │       ├── AGENTS.md
    │       ├── README.md
    │       ├── eslint.config.js
    │       ├── index.html
    │       ├── package.json
    │       ├── src/
    │       │   ├── app/
    │       │   │   ├── api/
    │       │   │   │   ├── baseApi.ts
    │       │   │   │   ├── baseQuery.ts
    │       │   │   │   └── baseQueryWithReauth.ts
    │       │   │   ├── model/
    │       │   │   │   └── store.ts
    │       │   │   └── ui/
    │       │   │       ├── App/
    │       │   │       │   ├── App.module.css
    │       │   │       │   └── App.tsx
    │       │   │       └── MainPage/
    │       │   │           └── MainPage.tsx
    │       │   ├── common/
    │       │   │   ├── components/
    │       │   │   │   ├── Header/
    │       │   │   │   │   ├── Header.module.css
    │       │   │   │   │   └── Header.tsx
    │       │   │   │   ├── LinearProgress/
    │       │   │   │   │   ├── LinearProgress.module.css
    │       │   │   │   │   └── LinearProgress.tsx
    │       │   │   │   ├── PageNotFound/
    │       │   │   │   │   ├── PageNotFound.module.css
    │       │   │   │   │   └── PageNotFound.tsx
    │       │   │   │   ├── Pagination/
    │       │   │   │   │   ├── Pagination.module.css
    │       │   │   │   │   └── Pagination.tsx
    │       │   │   │   └── index.tsx
    │       │   │   ├── constants/
    │       │   │   │   ├── constants.ts
    │       │   │   │   └── index.ts
    │       │   │   ├── enums/
    │       │   │   │   ├── enums.ts
    │       │   │   │   └── index.ts
    │       │   │   ├── hooks/
    │       │   │   │   ├── index.ts
    │       │   │   │   ├── useDebounceValue.ts
    │       │   │   │   ├── useGlobalLoading.ts
    │       │   │   │   └── useInfiniteScroll.ts
    │       │   │   ├── routing/
    │       │   │   │   ├── Routing.tsx
    │       │   │   │   └── index.ts
    │       │   │   ├── schemas/
    │       │   │   │   ├── index.ts
    │       │   │   │   └── schemas.ts
    │       │   │   ├── socket/
    │       │   │   │   ├── getSocket.ts
    │       │   │   │   ├── index.ts
    │       │   │   │   └── subscribeToEvent.ts
    │       │   │   ├── types/
    │       │   │   │   ├── index.ts
    │       │   │   │   └── types.ts
    │       │   │   └── utils/
    │       │   │       ├── errorToast.ts
    │       │   │       ├── getPaginationPages.ts
    │       │   │       ├── handleErrors.ts
    │       │   │       ├── index.ts
    │       │   │       ├── isErrorWithDetailArray.ts
    │       │   │       ├── isErrorWithProperty.ts
    │       │   │       ├── isTokens.ts
    │       │   │       ├── trimToMaxLength.ts
    │       │   │       └── withZodCatch.ts
    │       │   ├── features/
    │       │   │   ├── auth/
    │       │   │   │   ├── api/
    │       │   │   │   │   ├── authApi.ts
    │       │   │   │   │   └── authApi.types.ts
    │       │   │   │   ├── model/
    │       │   │   │   │   └── auth.schemas.ts
    │       │   │   │   └── ui/
    │       │   │   │       ├── Login/
    │       │   │   │       │   └── Login.tsx
    │       │   │   │       ├── OAuthCallback/
    │       │   │   │       │   └── OAuthCallback.tsx
    │       │   │   │       └── ProfilePage/
    │       │   │   │           ├── ProfilePage.module.css
    │       │   │   │           └── ProfilePage.tsx
    │       │   │   ├── playlists/
    │       │   │   │   ├── api/
    │       │   │   │   │   ├── playlistsApi.ts
    │       │   │   │   │   └── playlistsApi.types.ts
    │       │   │   │   ├── model/
    │       │   │   │   │   └── playlists.schemas.ts
    │       │   │   │   └── ui/
    │       │   │   │       ├── CreatePlaylistForm/
    │       │   │   │       │   ├── CreatePlaylistForm.module.css
    │       │   │   │       │   └── CreatePlaylistForm.tsx
    │       │   │   │       ├── EditPlaylistForm/
    │       │   │   │       │   └── EditPlaylistForm.tsx
    │       │   │   │       ├── PlaylistItem/
    │       │   │   │       │   ├── PlaylistCover/
    │       │   │   │       │   │   ├── PlaylistCover.module.css
    │       │   │   │       │   │   └── PlaylistCover.tsx
    │       │   │   │       │   ├── PlaylistDescription/
    │       │   │   │       │   │   └── PlaylistDescription.tsx
    │       │   │   │       │   └── PlaylistItem.tsx
    │       │   │   │       ├── PlaylistsList/
    │       │   │   │       │   ├── PlaylistsList.module.css
    │       │   │   │       │   └── PlaylistsList.tsx
    │       │   │   │       ├── PlaylistsPage.module.css
    │       │   │   │       └── PlaylistsPage.tsx
    │       │   │   └── tracks/
    │       │   │       ├── api/
    │       │   │       │   ├── tracksApi.ts
    │       │   │       │   └── tracksApi.types.ts
    │       │   │       ├── model/
    │       │   │       │   └── tracks.schemas.ts
    │       │   │       └── ui/
    │       │   │           ├── LoadingTrigger/
    │       │   │           │   └── LoadingTrigger.tsx
    │       │   │           ├── TracksList/
    │       │   │           │   ├── TracksList.module.css
    │       │   │           │   └── TracksList.tsx
    │       │   │           └── TracksPage.tsx
    │       │   ├── index.css
    │       │   ├── main.tsx
    │       │   └── vite-env.d.ts
    │       ├── tsconfig.app.json
    │       ├── tsconfig.json
    │       ├── tsconfig.node.json
    │       └── vite.config.ts
    └── tanstack-query-router-fsd/
        └── lesson1/
            ├── .gitignore
            ├── README.md
            ├── eslint.config.js
            ├── index.html
            ├── package.json
            ├── src/
            │   ├── app/
            │   │   ├── entrypoint/
            │   │   │   └── main.tsx
            │   │   ├── layouts/
            │   │   │   ├── root-layout.module.css
            │   │   │   └── root-layout.tsx
            │   │   ├── routes/
            │   │   │   ├── __root.tsx
            │   │   │   ├── index.tsx
            │   │   │   ├── my-playlists.tsx
            │   │   │   ├── oauth/
            │   │   │   │   └── callback.tsx
            │   │   │   └── routeTree.gen.ts
            │   │   ├── styles/
            │   │   │   ├── index.css
            │   │   │   └── reset.css
            │   │   ├── tanstack-query/
            │   │   │   └── query-client-instance.tsx
            │   │   └── tanstack-router/
            │   │       └── router-instance.tsx
            │   ├── features/
            │   │   ├── auth/
            │   │   │   ├── api/
            │   │   │   │   ├── use-login-mutation.tsx
            │   │   │   │   ├── use-logout-mutation.tsx
            │   │   │   │   └── use-me-query.ts
            │   │   │   └── ui/
            │   │   │       ├── account-bar.module.css
            │   │   │       ├── account-bar.tsx
            │   │   │       ├── current-user/
            │   │   │       │   └── current-user.tsx
            │   │   │       ├── login-button.tsx
            │   │   │       └── logout-button.tsx
            │   │   └── playlists/
            │   │       ├── add-playlist/
            │   │       │   ├── api/
            │   │       │   │   └── use-add-playlist-mutation.ts
            │   │       │   └── ui/
            │   │       │       └── add-playlist-form.tsx
            │   │       ├── delete-playlist/
            │   │       │   ├── api/
            │   │       │   │   └── use-delete-mutation.ts
            │   │       │   └── ui/
            │   │       │       └── delete-playlist.tsx
            │   │       └── edit-playlist/
            │   │           ├── api/
            │   │           │   ├── use-playlist-query.tsx
            │   │           │   └── use-update-playlist-mutation.ts
            │   │           └── ui/
            │   │               └── edit-playlist-form.tsx
            │   ├── pages/
            │   │   ├── auth/
            │   │   │   └── oauth-callback-page.tsx
            │   │   ├── my-playlists-page.tsx
            │   │   └── playlists-page.tsx
            │   ├── shared/
            │   │   ├── api/
            │   │   │   ├── client.ts
            │   │   │   ├── keys-factories/
            │   │   │   │   ├── auth-keys-factory.ts
            │   │   │   │   └── playlists-keys-factory.ts
            │   │   │   └── schema.ts
            │   │   ├── config/
            │   │   │   ├── api-config.ts
            │   │   │   └── localstorage-keys.ts
            │   │   ├── ui/
            │   │   │   ├── header/
            │   │   │   │   ├── header.module.css
            │   │   │   │   └── header.tsx
            │   │   │   ├── pagination/
            │   │   │   │   ├── pagination-nav/
            │   │   │   │   │   ├── pagination-nav.module.css
            │   │   │   │   │   └── pagination-nav.tsx
            │   │   │   │   ├── pagination.module.css
            │   │   │   │   ├── pagination.tsx
            │   │   │   │   └── utils/
            │   │   │   │       └── get-pagination-pages.ts
            │   │   │   └── util/
            │   │   │       └── query-error-handler-for-rhf-factory.ts
            │   │   └── util/
            │   │       └── json-api-error.ts
            │   ├── vite-env.d.ts
            │   └── widgets/
            │       └── playlists/
            │           ├── api/
            │           │   └── use-playlists-query.ts
            │           └── ui/
            │               └── playlists.tsx
            ├── tsconfig.app.json
            ├── tsconfig.json
            ├── tsconfig.node.json
            ├── tsr.config.json
            └── vite.config.ts

================================================
FILE CONTENTS
================================================

================================================
FILE: .github/workflows/ci-rtk.yml
================================================
name: CI - RTK Query Build

on:
  push:
    branches:
      - develop
    paths:
      - 'apps/rtk-query/**'
  pull_request:
    paths:
      - 'apps/rtk-query/**'

jobs:
  build:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4

      - uses: actions/setup-node@v4
        with:
          node-version: lts/*

      - uses: pnpm/action-setup@v4
        with:
          run_install: false

      - name: Install dependencies
        working-directory: apps/rtk-query
        run: pnpm install --no-frozen-lockfile

      - name: Build app
        working-directory: apps/rtk-query
        run: pnpm build


================================================
FILE: .github/workflows/ci-tanstack.yml
================================================
name: CI - TanStack Query Build

on:
  push:
    branches:
      - develop
    paths:
      - 'apps/tanstack-query-zustand/**'
  pull_request:
    paths:
      - 'apps/tanstack-query-zustand/**'

jobs:
  build:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4

      - uses: actions/setup-node@v4
        with:
          node-version: lts/*

      - uses: pnpm/action-setup@v4
        with:
          run_install: false

      - name: Install dependencies
        working-directory: apps/tanstack-query-zustand
        run: pnpm install --no-frozen-lockfile

      - name: Build app
        working-directory: apps/tanstack-query-zustand
        run: pnpm build


================================================
FILE: .github/workflows/deploy-effector.yml
================================================
name: Deploy Effector App

on:
  workflow_dispatch:

concurrency:
  group: gh-pages-deploy
  cancel-in-progress: false

permissions:
  contents: write

jobs:
  deploy:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4

      - uses: actions/setup-node@v4
        with:
          node-version: lts/*

      - uses: pnpm/action-setup@v4
        with:
          run_install: false

      - name: Install dependencies
        working-directory: apps/react-effector-fsd
        run: pnpm install --no-frozen-lockfile

      - name: Build app
        working-directory: apps/react-effector-fsd
        run: pnpm build

      - name: Create SPA fallback
        working-directory: apps/react-effector-fsd/dist
        run: cp index.html 404.html

      - name: Deploy to GitHub Pages
        uses: JamesIves/github-pages-deploy-action@v4
        with:
          folder: apps/react-effector-fsd/dist
          target-folder: effector
          clean: false
          branch: gh-pages


================================================
FILE: .github/workflows/deploy-reatom.yml
================================================
name: Deploy Reatom App

on:
  workflow_dispatch:

concurrency:
  group: gh-pages-deploy
  cancel-in-progress: false

permissions:
  contents: write

jobs:
  deploy:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4

      - uses: actions/setup-node@v4
        with:
          node-version: lts/*

      - uses: pnpm/action-setup@v4
        with:
          run_install: false

      - name: Install dependencies
        working-directory: apps/reatom
        run: pnpm install --no-frozen-lockfile

      - name: Build app
        working-directory: apps/reatom
        run: pnpm build

      - name: Create SPA fallback
        working-directory: apps/reatom/dist
        run: cp index.html 404.html

      - name: Deploy to GitHub Pages
        uses: JamesIves/github-pages-deploy-action@v4
        with:
          folder: apps/reatom/dist
          target-folder: reatom
          clean: false
          branch: gh-pages


================================================
FILE: .github/workflows/deploy-root.yml
================================================
name: Deploy Root Landing Page

on:
  workflow_dispatch:

concurrency:
  group: gh-pages-deploy
  cancel-in-progress: false

permissions:
  contents: write

jobs:
  deploy:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4

      - name: Prepare root files
        run: |
          mkdir -p temp-root
          cp public/index.html temp-root/
          cp public/404.html temp-root/
          echo 'stg.musicfun.dev' > temp-root/CNAME
          touch temp-root/.nojekyll

      - name: Deploy to GitHub Pages
        uses: JamesIves/github-pages-deploy-action@v4
        with:
          folder: temp-root
          target-folder: .
          clean: false
          clean-exclude: |
            tanstackquery/
            rtkquery/
            reatom/
            effector/
          branch: gh-pages


================================================
FILE: .github/workflows/deploy-rtk.yml
================================================
name: Deploy RTK Query App

on:
  workflow_dispatch:

concurrency:
  group: gh-pages-deploy
  cancel-in-progress: false

permissions:
  contents: write

jobs:
  deploy:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4

      - uses: actions/setup-node@v4
        with:
          node-version: lts/*

      - uses: pnpm/action-setup@v4
        with:
          run_install: false

      - name: Install dependencies
        working-directory: apps/rtk-query
        run: pnpm install --no-frozen-lockfile

      - name: Build app
        working-directory: apps/rtk-query
        run: pnpm build

      - name: Create SPA fallback
        working-directory: apps/rtk-query/dist
        run: cp index.html 404.html

      - name: Deploy to GitHub Pages
        uses: JamesIves/github-pages-deploy-action@v4
        with:
          folder: apps/rtk-query/dist
          target-folder: rtkquery
          clean: false
          branch: gh-pages


================================================
FILE: .github/workflows/deploy-tanstack.yml
================================================
name: Deploy TanStack Query App

on:
  workflow_dispatch:

concurrency:
  group: gh-pages-deploy
  cancel-in-progress: false

permissions:
  contents: write

jobs:
  deploy:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4

      - uses: actions/setup-node@v4
        with:
          node-version: lts/*

      - uses: pnpm/action-setup@v4
        with:
          run_install: false

      - name: Install dependencies
        working-directory: apps/tanstack-query-zustand
        run: pnpm install --no-frozen-lockfile

      - name: Build app
        working-directory: apps/tanstack-query-zustand
        run: pnpm build

      - name: Create SPA fallback
        working-directory: apps/tanstack-query-zustand/dist
        run: cp index.html 404.html

      - name: Deploy to GitHub Pages
        uses: JamesIves/github-pages-deploy-action@v4
        with:
          folder: apps/tanstack-query-zustand/dist
          target-folder: tanstackquery
          clean: false
          branch: gh-pages


================================================
FILE: .github/workflows/deploy.yml
================================================
name: Deploy MusicFun Apps to GitHub Pages

on:
  workflow_dispatch:

permissions:
  contents: read
  pages: write
  id-token: write

concurrency:
  group: pages-deploy
  cancel-in-progress: true

jobs:
  deploy:
    runs-on: ubuntu-latest
    environment:
      name: github-pages
      url: ${{ steps.deployment.outputs.page_url }}

    steps:
      - uses: actions/checkout@v4

      - uses: actions/setup-node@v4
        with:
          node-version: lts/*

      - uses: pnpm/action-setup@v4
        with:
          run_install: false

      # === Install ===

      - name: Install deps for tanstack-query (folder renamed)
        working-directory: apps/tanstack-query-zustand
        run: pnpm install --no-frozen-lockfile

      - name: Install deps for rtk-query
        working-directory: apps/rtk-query
        run: pnpm install --no-frozen-lockfile

      - name: Install deps for reatom
        working-directory: apps/reatom
        run: pnpm install --no-frozen-lockfile

      - name: Install deps for effector
        working-directory: apps/react-effector-fsd
        run: pnpm install --no-frozen-lockfile

      # === Build ===

      - name: Build tanstack-query
        working-directory: apps/tanstack-query-zustand
        run: pnpm build

      - name: Build rtk-query
        working-directory: apps/rtk-query
        run: pnpm build

      - name: Build reatom
        working-directory: apps/reatom
        run: pnpm build

      - name: Build effector
        working-directory: apps/react-effector-fsd
        run: pnpm build

      # === Pages config ===

      - uses: actions/configure-pages@v5
        with:
          enablement: true

      # === SPA fallback ===

      - name: SPA fallback for tanstack-query
        working-directory: apps/tanstack-query-zustand/dist
        run: cp index.html 404.html

      - name: SPA fallback for rtk-query
        working-directory: apps/rtk-query/dist
        run: cp index.html 404.html

      - name: SPA fallback for reatom
        working-directory: apps/reatom/dist
        run: cp index.html 404.html

      - name: SPA fallback for effector
        working-directory: apps/react-effector-fsd/dist
        run: cp index.html 404.html

      # === Prepare deploy folder ===

      - name: Prepare deployment folder
        run: |
          mkdir -p dist/tanstackquery
          mkdir -p dist/rtkquery
          mkdir -p dist/reatom
          mkdir -p dist/effector

          cp -r apps/tanstack-query-zustand/dist/* dist/tanstackquery/
          cp -r apps/rtk-query/dist/* dist/rtkquery/
          cp -r apps/reatom/dist/* dist/reatom/
          cp -r apps/react-effector-fsd/dist/* dist/effector/

          touch dist/.nojekyll

      # === Root pages ===

      - name: Copy root index.html
        run: cp public/index.html dist/index.html

      - name: Copy root 404.html
        run: cp public/404.html dist/404.html

      - name: Add CNAME
        run: echo 'stg.musicfun.dev' > dist/CNAME

      - uses: actions/upload-pages-artifact@v3
        with:
          path: dist

      - id: deployment
        uses: actions/deploy-pages@v4


================================================
FILE: .gitignore
================================================
# Logs
logs
*.log
npm-debug.log*
yarn-debug.log*
yarn-error.log*
pnpm-debug.log*
lerna-debug.log*

node_modules
dist
dist-ssr
*.local

# Editor directories and files
.vscode/*
!.vscode/extensions.json
.idea
.cursor
.DS_Store
*.suo
*.ntvs*
*.njsproj
*.sln
*.sw?
.cursorignore

# env files
.env.local
.env.development.local
.env.test.local
.env.production.local


================================================
FILE: .husky/pre-commit
================================================
# ─── Auto-increment VITE_VERSION for rtk-query ──────────────────────────────
#
# If any staged file inside apps/rtk-query/ changed (excluding .env itself),
# bump VITE_VERSION in .env by 1 and stage the updated file.
# ─────────────────────────────────────────────────────────────────────────────

ENV_FILE="apps/rtk-query/.env"

if git diff --cached --name-only -- 'apps/rtk-query/' | grep -qv '\.env$'; then
  CURRENT=$(grep "^VITE_VERSION=" "$ENV_FILE" | cut -d'=' -f2)
  NEW=$((CURRENT + 1))
  sed -i '' "s/^VITE_VERSION=.*/VITE_VERSION=$NEW/" "$ENV_FILE"
  git add "$ENV_FILE"
  echo "✔ Bumped rtk-query VITE_VERSION: $CURRENT → $NEW"
fi

pnpm exec lint-staged


================================================
FILE: .husky/pre-push
================================================
#!/usr/bin/env sh

# This script runs automatically before every "git push".
# If any build fails, the push is cancelled — broken code won't reach the remote.

# ─── Step 1: Figure out which files were changed ───────────────────────────────
#
# @{push} is a git shorthand for "the branch on the remote that we're pushing to".
# "git diff --name-only @{push}.." compares the remote state with our local HEAD
# and outputs just the file paths (one per line) that differ.
#
# 2>/dev/null suppresses errors — for example, if the branch has no remote tracking
# branch yet (first push), this command would fail.
#
# If it fails, we fall back to "git diff --name-only HEAD~1" which compares
# the latest commit with the one before it (so at least we check the last commit).
# ───────────────────────────────────────────────────────────────────────────────
CHANGED=$(git diff --name-only @{push}.. 2>/dev/null || git diff --name-only HEAD~1)

# ─── Step 2: Initialize flags for each project ────────────────────────────────
#
# We use two boolean flags to track whether each project needs to be built.
# They start as "false" and will be set to "true" if relevant files were changed.
# ───────────────────────────────────────────────────────────────────────────────
RTK=false
TANSTACK=false

# ─── Step 3: Check which projects have changed files ──────────────────────────
#
# We pipe the list of changed files into grep.
#   -q flag means "quiet" — grep won't print anything, it just sets the exit code:
#     exit 0 (success) if a match is found, exit 1 (failure) if not.
#
# "^apps/rtk-query/" means "line starts with apps/rtk-query/" — so any file
# inside that folder will match.
#
# "&&" means "if the previous command succeeded (match found), run the next command".
# So if any changed file is inside apps/rtk-query/, we set RTK=true.
# Same logic for tanstack-query-zustand.
# ───────────────────────────────────────────────────────────────────────────────
echo "$CHANGED" | grep -q "^apps/rtk-query/" && RTK=true
echo "$CHANGED" | grep -q "^apps/tanstack-query-zustand/" && TANSTACK=true

# ─── Step 4: Type-check only the projects that were changed ───────────────────
#
# We run only "tsc -b" (TypeScript compiler in build mode) instead of a full
# "pnpm build" (which would also run Vite bundling). tsc catches type errors,
# missing imports, wrong props, etc. Vite build is redundant here — it doesn't
# check types, just bundles JS. Full build is done in CI instead.
#
# "|| exit 1" means: if tsc fails (returns non-zero exit code),
# immediately exit this script with code 1. A non-zero exit from a pre-push
# hook tells git to ABORT the push. This prevents pushing broken code.
# ───────────────────────────────────────────────────────────────────────────────

if [ "$RTK" = true ]; then
  echo "▶ Type-checking rtk-query..."
  pnpm --prefix apps/rtk-query exec tsc -b || exit 1
fi

if [ "$TANSTACK" = true ]; then
  echo "▶ Type-checking tanstack-query-zustand..."
  pnpm --prefix apps/tanstack-query-zustand exec tsc -b || exit 1
fi

# If we reach this point, either:
#   - No projects had changes (nothing to check), or
#   - All type checks passed.
# In both cases the script exits with code 0 (success) and git proceeds with the push.


================================================
FILE: .prettierignore
================================================
node_modules
dist
build
.next
.nuxt
coverage
*.log
pnpm-lock.yaml


================================================
FILE: .prettierrc
================================================
{
  "singleQuote": true,
  "tabWidth": 2,
  "trailingComma": "es5",
  "bracketSameLine": true,
  "arrowParens": "always",
  "endOfLine": "auto",
  "printWidth": 100,
  "semi": false
}


================================================
FILE: CONTRIBUTING.md
================================================
> [!NOTE]
> We prefer English language for all communication.

## Creating an issue

Before creating an issue please ensure that the problem is not [already reported](https://github.com/it-incubator/musicfun-react-all-stacks/issues).

If you want to report a bug, create a reproduction using StackBlitz or CodeSandbox. If you want to request a feature, add motivation section and some usage examples.

## Sending a Pull Request

1. fork and clone the repository
   > [!NOTE]
   > You can just clone the repository if you are a collaborator
2. create a development branch from `main`
3. run the following command in the project root (this will install dependencies for all apps and packages)
   > [!NOTE]
   > It is recommended to create a branch from the issue
4. [make changes](#coding-guide) and [commit them](#commit-messages)
5. upload feature branch and create a [Pull Request](https://github.com/it-incubator/musicfun-react-all-stacks/compare) to merge changes to `main`
6. link your PR to the issue using a [closing keyword](https://help.github.com/en/articles/closing-issues-using-keywords) or provide changes description with motivation and explanation in the comment (example: `fix #74`)
7. wait until a team member responds

## Coding guide

<!-- - always use `@ts-expect-error` instead of `@ts-ignore` -->

- use `// @ts-ignore` if you not sure why error appears or you think it could be better, use `// @ts-expect-error` if you sure that error is a mistake <!-- ??? -->

## Commit messages

Commit messages should follow the [Conventional Commits](https://conventionalcommits.org) specification:

```
<type>[optional scope]: <description>
```

### Allowed `<type>`

- `chore`: any repository maintainance changes
- `feat`: code change that adds a new feature
- `fix`: bug fix
- `perf`: code change that improves performance
- `refactor`: code change that is neither a feature addition nor a bug fix nor a performance improvement
- `docs`: documentation only changes
- `ci`: a change made to CI configurations and scripts
- `style`: cosmetic code change
- `test`: change that only adds or corrects tests
- `revert`: change that reverts previous commits

### Allowed `<scope>`

Package directory name. Eg: `/packages/effects` is scoped as `effects`.

### `<description>` rules

- should be written in English
- should be in imperative mood (like `change` instead `changed` or `changes`)
- should not be capitalized
- should not have period (`.`) at the end

### Commit message examples

```
docs: fix typo in npm-react
fix(core): add check for atoms with equal ids
```


================================================
FILE: FRONTEND_API_CHANGES.md
================================================
# Frontend API Changes - January 27-29, 2026

This document summarizes the API changes from the last 5 commits that require frontend updates.

---

## Table of Contents

1. [New Endpoints](#new-endpoints)
2. [Response Format Changes](#response-format-changes)
3. [Request Payload Changes (Breaking)](#request-payload-changes-breaking)

---

## New Endpoints

### 1. Get Playlists Count

**Endpoint:** `GET /playlists/count/:userId`

Returns the total number of playlists for a specific user.

**Response:**

```json
{
  "count": 5
}
```

**TypeScript Interface:**

```typescript
interface GetPlaylistsCountOutput {
  count: number
}
```

---

### 2. Get Tracks Count

**Endpoint:** `GET /playlists/tracks/count/:userId`

Returns the total number of **published** tracks for a specific user.

**Response:**

```json
{
  "count": 12
}
```

**TypeScript Interface:**

```typescript
interface GetTracksCountOutput {
  count: number
}
```

> **Note:** Only published tracks are counted. Draft/unpublished tracks are excluded.

---

## Response Format Changes

### 1. Playlists List - `description` Field Removed

**Endpoint:** `GET /playlists`

The `description` field has been **removed** from the playlist list response.

**Before:**

```json
{
  "data": [
    {
      "id": "...",
      "type": "playlists",
      "attributes": {
        "title": "My Playlist",
        "description": "Playlist description",  // ❌ REMOVED
        "tracksCount": 10,
        ...
      }
    }
  ]
}
```

**After:**

```json
{
  "data": [
    {
      "id": "...",
      "type": "playlists",
      "attributes": {
        "title": "My Playlist",
        "tracksCount": 10,
        ...
      }
    }
  ]
}
```

> **Note:** The `description` field is still available when fetching a **single playlist** via `GET /playlists/:playlistId`.

---

### 2. Playlists - New `tracksCount` Field

**Endpoints:**

- `GET /playlists` (list)
- `GET /playlists/:playlistId` (single)

A new `tracksCount` field has been added to playlist responses.

**Response:**

```json
{
  "data": {
    "id": "...",
    "type": "playlists",
    "attributes": {
      "title": "My Playlist",
      "tracksCount": 10,  // ✅ NEW FIELD
      ...
    }
  }
}
```

**TypeScript Update:**

```typescript
interface PlaylistAttributes {
  // ... existing fields
  tracksCount: number // NEW
}
```

---

### 3. Tags - JSON:API Format

**Endpoints:**

- `POST /tags` (create)
- `GET /tags/search` (search)

Tags endpoints now return JSON:API formatted responses.

**Before (Create):**

```json
{
  "id": "uuid",
  "name": "Rock"
}
```

**After (Create):**

```json
{
  "data": {
    "id": "uuid",
    "type": "tags",
    "attributes": {
      "name": "Rock"
    }
  }
}
```

**Before (Search):**

```json
[
  { "id": "uuid1", "name": "Rock" },
  { "id": "uuid2", "name": "Pop" }
]
```

**After (Search):**

```json
{
  "data": [
    {
      "id": "uuid1",
      "type": "tags",
      "attributes": { "name": "Rock" }
    },
    {
      "id": "uuid2",
      "type": "tags",
      "attributes": { "name": "Pop" }
    }
  ]
}
```

**TypeScript Interfaces:**

```typescript
interface TagAttributes {
  name: string
}

interface TagResource {
  id: string
  type: 'tags'
  attributes: TagAttributes
}

interface GetTagOutput {
  data: TagResource
}

interface GetTagsOutput {
  data: TagResource[]
}
```

---

## Request Payload Changes (Breaking)

All create/update endpoints now use **JSON:API format** for request bodies.

### 1. Create Tag

**Endpoint:** `POST /tags`

**Before:**

```json
{
  "name": "Rock"
}
```

**After:**

```json
{
  "data": {
    "type": "tags",
    "attributes": {
      "name": "Rock"
    }
  }
}
```

---

### 2. Create Artist

**Endpoint:** `POST /artists`

**Before:**

```json
{
  "name": "Artist Name"
}
```

**After:**

```json
{
  "data": {
    "type": "artists",
    "attributes": {
      "name": "Artist Name"
    }
  }
}
```

---

### 3. Create Playlist

**Endpoint:** `POST /playlists`

**Before:**

```json
{
  "title": "My Playlist",
  "description": "Description"
}
```

**After:**

```json
{
  "data": {
    "type": "playlists",
    "attributes": {
      "title": "My Playlist",
      "description": "Description"
    }
  }
}
```

---

### 4. Update Playlist

**Endpoint:** `PUT /playlists/:id`

**Before:**

```json
{
  "title": "Updated Title",
  "description": "Updated description"
}
```

**After:**

```json
{
  "data": {
    "type": "playlists",
    "attributes": {
      "title": "Updated Title",
      "description": "Updated description"
    }
  }
}
```

---

### 5. Upload Track

**Endpoint:** `POST /tracks` (multipart/form-data)

**Before:**

```
title: "Track Title"
artists: ["artist-id-1", "artist-id-2"]
tags: ["tag-id-1"]
```

**After:**

```
data[type]: "tracks"
data[attributes][title]: "Track Title"
data[attributes][artists]: ["artist-id-1", "artist-id-2"]
data[attributes][tags]: ["tag-id-1"]
```

---

### 6. Update Track

**Endpoint:** `PATCH /tracks/:id`

**Before:**

```json
{
  "title": "Updated Title",
  "artists": ["artist-id"],
  "tags": ["tag-id"]
}
```

**After:**

```json
{
  "data": {
    "type": "tracks",
    "attributes": {
      "title": "Updated Title",
      "artists": ["artist-id"],
      "tags": ["tag-id"]
    }
  }
}
```

---

### 7. Add Track to Playlist

**Endpoint:** `POST /playlists/:id/tracks`

**Before:**

```json
{
  "trackId": "track-uuid"
}
```

**After:**

```json
{
  "data": {
    "type": "playlist-tracks",
    "attributes": {
      "trackId": "track-uuid"
    }
  }
}
```

---

## Summary of Breaking Changes

| Category        | Change                                              | Impact                                              |
| --------------- | --------------------------------------------------- | --------------------------------------------------- |
| Request Format  | All create/update payloads now use JSON:API wrapper | **HIGH** - All POST/PUT/PATCH requests need updates |
| Response Format | Tags endpoints now return JSON:API format           | **MEDIUM** - Update tag parsing logic               |
| Response Format | Playlist list no longer includes `description`      | **LOW** - Remove usage or fetch single playlist     |
| New Field       | `tracksCount` added to playlist responses           | **LOW** - Can be used for UI display                |
| New Endpoints   | `/playlists/count/:userId`                          | **NONE** - New feature                              |
| New Endpoints   | `/playlists/tracks/count/:userId`                   | **NONE** - New feature                              |

---

## Migration Checklist

- [ ] Update all API request payloads to JSON:API format
- [ ] Update tag response parsing (access via `response.data` / `response.data.attributes`)
- [ ] Remove reliance on `description` field in playlist lists
- [ ] Add `tracksCount` to playlist TypeScript interfaces
- [ ] (Optional) Implement new count endpoints for user statistics

---

## TypeScript Helper Types

```typescript
// Generic JSON:API Request Wrapper
interface JsonApiRequest<T extends string, A> {
  data: {
    type: T
    attributes: A
  }
}

// Example usage:
type CreateTagRequest = JsonApiRequest<'tags', { name: string }>
type CreatePlaylistRequest = JsonApiRequest<
  'playlists',
  {
    title: string
    description: string | null
  }
>
type CreateArtistRequest = JsonApiRequest<'artists', { name: string }>
type UpdateTrackRequest = JsonApiRequest<
  'tracks',
  {
    title?: string
    artists?: string[]
    tags?: string[]
  }
>
```


================================================
FILE: README.md
================================================
[Figma](https://www.figma.com/design/AxTPd4AS8oAgdEF4dDgLis/MusicFun?node-id=9-353&p=f&t=I0svXbRE8kPWOUFB-0) • [ApiHub](https://apihub.it-incubator.io/en) • [Swagger](https://musicfun.it-incubator.app/api)

# 🚀 Project Launch

Information on launching projects can be found in the `README.md` of each individual repository.

## Actual projects

- `youtube/rtk-query` - youtube lessons: rtk-query

- `youtube/tanstack-query-router-fsd` - youtube lessons: tanstack-query

- `apps/musicfun-ui-vanilla` - full project html/css/storybook vanilla without ui libraries

- `apps/musicfun-tanstack-query` - full project with tanstack query

- `apps/musicfun-rtk-query` - full project with rtk-query

## ❌ Project Launch with SDK (Currently Unsupported)

### 1. Installing Dependencies

Run the following command in the project root (this will install dependencies for all apps and packages):

```bash
pnpm i
```

### 2. SDK build

Then build `musicfun-api-sdk`

```bash
pnpm build:sdk
```

️⚠️ Note: Some scripts may not be cross-platform compatible:

```json
"scripts": {
"clean": "rm -rf dist",
"build": "pnpm run clean && tsc"
}
```

If so, try a simpler alternative command:

```bash
pnpm build:sdk:simple
```

### 3. Starting the Project

- 🎶musicfun на **tanstack**

```bash
   pnpm start:musicfun-tanstack
```

- 🎶musicfun на **rtk-query**

```bash
    pnpm start:musicfun-rtk
```

- 🎶musicfun на **nextjs**

```bash
     pnpm start:musicfun-nextjs
```

## ✅ Рекомендованные форматы нейминга файлов в React/TypeScript проектах

| Category              | Recommended Format | Example                               |
| --------------------- | ------------------ | ------------------------------------- |
| **Components**        | `PascalCase`       | `UserCard.tsx`                        |
| **Hooks**             | `camelCase`        | `useAuth.ts`                          |
| **Utilities (utils)** | `kebab-case`       | `format-date.ts`, `validate-email.ts` |
| **Redux Slice/State** | `kebab-case`       | `auth-slice.ts`, `user-slice.ts`      |
| **API files**         | `kebab-case`       | `playlists-api.ts`, `auth-api.ts`     |
| **Types/Interfaces**  | `kebab-case`       | `user.types.ts`, `auth.types.ts`      |
| **Services**          | `kebab-case`       | `auth-service.ts`, `user-service.ts`  |
| **Mocks (mock data)** | `kebab-case`       | `user-mocks.ts`, `playlist-mocks.ts`  |

## Contributing

Please refer to our [Contributing guide](CONTRIBUTING.md) to learn about our development process, how to propose bugfixes

### Happy hacking 🚀 🚀🚀


================================================
FILE: apps/nextjs/.gitignore
================================================
# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.

# dependencies
/node_modules
/.pnp
.pnp.*
.yarn/*
!.yarn/patches
!.yarn/plugins
!.yarn/releases
!.yarn/versions

# testing
/coverage

# next.js
/.next/
/out/

# production
/build

# misc
.DS_Store
*.pem

# debug
npm-debug.log*
yarn-debug.log*
yarn-error.log*
.pnpm-debug.log*

# env files (can opt-in for committing if needed)
.env*.local

# vercel
.vercel

# typescript
*.tsbuildinfo
next-env.d.ts


================================================
FILE: apps/nextjs/README.md
================================================
This is a [Next.js](https://nextjs.org) project bootstrapped with [`create-next-app`](https://nextjs.org/docs/app/api-reference/cli/create-next-app).

## Getting Started

First, run the development server:

```bash
npm run dev
# or
yarn dev
# or
pnpm dev
# or
bun dev
```

Open [http://localhost:3000](http://localhost:3000) with your browser to see the result.

You can start editing the page by modifying `app/page.tsx`. The page auto-updates as you edit the file.

This project uses [`next/font`](https://nextjs.org/docs/app/building-your-application/optimizing/fonts) to automatically optimize and load [Geist](https://vercel.com/font), a new font family for Vercel.

## Learn More

To learn more about Next.js, take a look at the following resources:

- [Next.js Documentation](https://nextjs.org/docs) - learn about Next.js features and API.
- [Learn Next.js](https://nextjs.org/learn) - an interactive Next.js tutorial.

You can check out [the Next.js GitHub repository](https://github.com/vercel/next.js) - your feedback and contributions are welcome!

## Deploy on Vercel

The easiest way to deploy your Next.js app is to use the [Vercel Platform](https://vercel.com/new?utm_medium=default-template&filter=next.js&utm_source=create-next-app&utm_campaign=create-next-app-readme) from the creators of Next.js.

Check out our [Next.js deployment documentation](https://nextjs.org/docs/app/building-your-application/deploying) for more details.


================================================
FILE: apps/nextjs/eslint.config.mjs
================================================
import { FlatCompat } from '@eslint/eslintrc'
import { dirname } from 'path'
import { fileURLToPath } from 'url'

const __filename = fileURLToPath(import.meta.url)
const __dirname = dirname(__filename)

const compat = new FlatCompat({
  baseDirectory: __dirname,
})

const eslintConfig = [...compat.extends('next/core-web-vitals', 'next/typescript')]

export default eslintConfig


================================================
FILE: apps/nextjs/next.config.ts
================================================
import type { NextConfig } from 'next'

const nextConfig: NextConfig = {
  /* config options here */
}

export default nextConfig


================================================
FILE: apps/nextjs/package.json
================================================
{
  "name": "musicfun-nextjs",
  "version": "0.1.0",
  "private": true,
  "scripts": {
    "dev": "NODE_OPTIONS='--inspect' next dev",
    "build": "next build",
    "start": "next start",
    "lint": "next lint"
  },
  "dependencies": {
    "react": "^19.0.0",
    "react-dom": "^19.0.0",
    "next": "15.3.3",
    "@it-incubator/musicfun-api-sdk": "workspace:*"
  },
  "devDependencies": {
    "typescript": "^5",
    "@types/node": "^20",
    "@types/react": "^19",
    "@types/react-dom": "^19"
  }
}


================================================
FILE: apps/nextjs/src/app/actions/auth/logout.action.tsx
================================================
'use server'
import { cookies } from 'next/headers'

export async function logout() {
  const cookieStore = await cookies()
  // удаляем куки, задав maxAge: 0
  cookieStore.set('access-token', '', { httpOnly: true, maxAge: 0, path: '/' })
  cookieStore.set('refresh-token', '', { httpOnly: true, maxAge: 0, path: '/' })
}


================================================
FILE: apps/nextjs/src/app/api/oauth/callback/route.ts
================================================
import { cookies } from 'next/headers'
import { NextResponse } from 'next/server'

import { authApi } from '@/shared/api/auth-api'
import { redirectAfterOauthUri } from '@/shared/api/base'
import { createAccessTokenCookie, createRefreshTokenCookie } from '@/shared/utils/cookieHelpers'

export async function GET(request: Request) {
  const { searchParams } = new URL(request.url)
  const code = searchParams.get('code') as string

  const tokens = await authApi.login({
    code,
    redirectUri: redirectAfterOauthUri,
    accessTokenTTL: '1d',
    rememberMe: true,
  })

  const cookieStore = await cookies()

  cookieStore.set(createRefreshTokenCookie(tokens.refreshToken))
  cookieStore.set(createAccessTokenCookie(tokens.accessToken))

  return NextResponse.redirect(new URL('/', request.url), 307)
}


================================================
FILE: apps/nextjs/src/app/globals.css
================================================
:root {
  --background: #ffffff;
  --foreground: #171717;
}

@media (prefers-color-scheme: dark) {
  :root {
    --background: #0a0a0a;
    --foreground: #ededed;
  }
}

html,
body {
  max-width: 100vw;
  overflow-x: hidden;
}

body {
  color: var(--foreground);
  background: var(--background);
  font-family: Arial, Helvetica, sans-serif;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
}

* {
  box-sizing: border-box;
  padding: 0;
  margin: 0;
}

a {
  color: inherit;
  text-decoration: none;
}

@media (prefers-color-scheme: dark) {
  html {
    color-scheme: dark;
  }
}


================================================
FILE: apps/nextjs/src/app/layout.tsx
================================================
import './globals.css'

import type { Metadata } from 'next'
import { Geist, Geist_Mono } from 'next/font/google'

const geistSans = Geist({
  variable: '--font-geist-sans',
  subsets: ['latin'],
})

const geistMono = Geist_Mono({
  variable: '--font-geist-mono',
  subsets: ['latin'],
})

export const metadata: Metadata = {
  title: 'Create Next App',
  description: 'Generated by create next app',
}

export default function RootLayout({
  children,
}: Readonly<{
  children: React.ReactNode
}>) {
  return (
    <html lang="en">
      <body className={`${geistSans.variable} ${geistMono.variable}`}>{children}</body>
    </html>
  )
}


================================================
FILE: apps/nextjs/src/app/page.module.css
================================================
.page {
  --gray-rgb: 0, 0, 0;
  --gray-alpha-200: rgba(var(--gray-rgb), 0.08);
  --gray-alpha-100: rgba(var(--gray-rgb), 0.05);

  --button-primary-hover: #383838;
  --button-secondary-hover: #f2f2f2;

  display: grid;
  grid-template-rows: 20px 1fr 20px;
  align-items: center;
  justify-items: center;
  min-height: 100svh;
  padding: 80px;
  gap: 64px;
  font-family: var(--font-geist-sans);
}

@media (prefers-color-scheme: dark) {
  .page {
    --gray-rgb: 255, 255, 255;
    --gray-alpha-200: rgba(var(--gray-rgb), 0.145);
    --gray-alpha-100: rgba(var(--gray-rgb), 0.06);

    --button-primary-hover: #ccc;
    --button-secondary-hover: #1a1a1a;
  }
}

.main {
  display: flex;
  flex-direction: column;
  gap: 32px;
  grid-row-start: 2;
}

.main ol {
  font-family: var(--font-geist-mono);
  padding-left: 0;
  margin: 0;
  font-size: 14px;
  line-height: 24px;
  letter-spacing: -0.01em;
  list-style-position: inside;
}

.main li:not(:last-of-type) {
  margin-bottom: 8px;
}

.main code {
  font-family: inherit;
  background: var(--gray-alpha-100);
  padding: 2px 4px;
  border-radius: 4px;
  font-weight: 600;
}

.ctas {
  display: flex;
  gap: 16px;
}

.ctas a {
  appearance: none;
  border-radius: 128px;
  height: 48px;
  padding: 0 20px;
  border: none;
  border: 1px solid transparent;
  transition:
    background 0.2s,
    color 0.2s,
    border-color 0.2s;
  cursor: pointer;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 16px;
  line-height: 20px;
  font-weight: 500;
}

a.primary {
  background: var(--foreground);
  color: var(--background);
  gap: 8px;
}

a.secondary {
  border-color: var(--gray-alpha-200);
  min-width: 158px;
}

.footer {
  grid-row-start: 3;
  display: flex;
  gap: 24px;
}

.footer a {
  display: flex;
  align-items: center;
  gap: 8px;
}

.footer img {
  flex-shrink: 0;
}

/* Enable hover only on non-touch devices */
@media (hover: hover) and (pointer: fine) {
  a.primary:hover {
    background: var(--button-primary-hover);
    border-color: transparent;
  }

  a.secondary:hover {
    background: var(--button-secondary-hover);
    border-color: transparent;
  }

  .footer a:hover {
    text-decoration: underline;
    text-underline-offset: 4px;
  }
}

@media (max-width: 600px) {
  .page {
    padding: 32px;
    padding-bottom: 80px;
  }

  .main {
    align-items: center;
  }

  .main ol {
    text-align: center;
  }

  .ctas {
    flex-direction: column;
  }

  .ctas a {
    font-size: 14px;
    height: 40px;
    padding: 0 16px;
  }

  a.secondary {
    min-width: auto;
  }

  .footer {
    flex-wrap: wrap;
    align-items: center;
    justify-content: center;
  }
}

@media (prefers-color-scheme: dark) {
  .logo {
    filter: invert();
  }
}


================================================
FILE: apps/nextjs/src/app/page.tsx
================================================
import { UserBlock } from '@/features/auth/ui/UserBlock'
import { tracksApi } from '@/shared/api/tracks/tracksApi'

import styles from './page.module.css'

export default async function Home() {
  const tracks = await tracksApi.fetchTracks({ pageNumber: 1, pageSize: 5 })

  return (
    <div className={styles.page}>
      <header>
        <UserBlock />
      </header>
      <h2>Tracks:</h2>
      {tracks.data.map((track) => (
        <li key={track.id}>{track.attributes.title}</li>
      ))}
    </div>
  )
}


================================================
FILE: apps/nextjs/src/app/profile/page.tsx
================================================
import { cookies } from 'next/headers'

import { authApi } from '@/shared/api/auth-api'
import { MeResponseResponse } from '@/shared/api/authApi.types'
import { redirectAfterOauthUri } from '@/shared/api/base'

export default async function ProfilePage() {
  let meData: MeResponseResponse | null = null
  try {
    meData = await authApi.getMe()
  } catch (error) {}

  return meData ? (
    <div>
      login: {meData.login}, userId: {meData.userId}
    </div>
  ) : (
    <div>Login</div>
  )
}


================================================
FILE: apps/nextjs/src/app/redirect/page.tsx
================================================
import { cookies } from 'next/headers'
import { redirect } from 'next/navigation'

import { authApi } from '@/shared/api/auth-api'
import { MeResponseResponse } from '@/shared/api/authApi.types'
import { redirectAfterOauthUri } from '@/shared/api/base'

export default async function ProfilePage() {
  let meData: MeResponseResponse | null = null
  try {
    meData = await authApi.getMe()
  } catch (error) {}

  if (meData) {
    redirect('/profile')
  } else {
    redirect('/')
  }
}


================================================
FILE: apps/nextjs/src/features/auth/ui/Login/Login.tsx
================================================
import { authApi } from '@/shared/api/auth-api'
import { redirectAfterOauthUri } from '@/shared/api/base'

export const Login = () => {
  return <a href={authApi.oauthUrl(redirectAfterOauthUri)}>Login via APIHUB</a>
}


================================================
FILE: apps/nextjs/src/features/auth/ui/Logout/Logout.tsx
================================================
'use client'
import { useRouter } from 'next/navigation'

import { logout } from '@/app/actions/auth/logout.action'

export const Logout = () => {
  const router = useRouter()
  const logoutHandler = async () => {
    await logout()
    router.push('/')
  }

  return <button onClick={logoutHandler}>logout</button>
}


================================================
FILE: apps/nextjs/src/features/auth/ui/MeInfo/MeInfo.tsx
================================================
import { Logout } from '@/features/auth/ui/Logout/Logout'
import { authApi } from '@/shared/api/auth-api'

export const MeInfo = async () => {
  const meData = await authApi.getMe()

  return (
    <div>
      userLogin: {meData.login}
      <Logout />
    </div>
  )
}


================================================
FILE: apps/nextjs/src/features/auth/ui/UserBlock.tsx
================================================
import { Login } from '@/features/auth/ui/Login/Login'
import { MeInfo } from '@/features/auth/ui/MeInfo/MeInfo'
import { authApi } from '@/shared/api/auth-api'
import { MeResponseResponse } from '@/shared/api/authApi.types'

export const UserBlock = async () => {
  let meData: MeResponseResponse | null = null
  try {
    meData = await authApi.getMe()
  } catch (error) {}

  return (
    <>
      {!meData && <Login />}
      {meData && <MeInfo />}
    </>
  )
}


================================================
FILE: apps/nextjs/src/middleware.ts
================================================
import { NextRequest, NextResponse } from 'next/server'

import { reauthMiddleware } from '@/reauth-middleware'

export async function middleware(request: NextRequest) {
  const url = request.nextUrl
  console.log('Middleware')
  const response = reauthMiddleware(request)
  if (response) return response

  return NextResponse.next()
}

export const config = {
  matcher: ['/', '/profile', '/api/:path*'], // или любой другой набор путей
}


================================================
FILE: apps/nextjs/src/reauth-middleware.ts
================================================
import { NextRequest, NextResponse } from 'next/server'

import { authApi } from '@/shared/api/auth-api'
import { createAccessTokenCookie, createRefreshTokenCookie } from '@/shared/utils/cookieHelpers'
import { getJwtExpirationMaxAge, getSecondsToExpiration } from '@/shared/utils/jwt-util'

const refreshTokens = async (refreshToken: string) => {
  try {
    const { accessToken, refreshToken: newRefreshToken } = await authApi.refreshToken({
      refreshToken,
    })
    return { accessToken, refreshToken: newRefreshToken }
  } catch {
    return null
  }
}

export async function reauthMiddleware(request: NextRequest) {
  const accessCookie = request.cookies.get('access-token')
  const refreshCookie = request.cookies.get('refresh-token')
  let tokens: { accessToken: string; refreshToken: string } | null = null

  if (accessCookie) {
    const secondsToExpiration = getSecondsToExpiration(accessCookie.value)
    if (secondsToExpiration < 20 && refreshCookie) {
      tokens = await refreshTokens(refreshCookie.value)
    }
  } else if (refreshCookie) {
    tokens = await refreshTokens(refreshCookie.value)
  }

  const requestHeaders = new Headers(request.headers)
  if (tokens) {
    requestHeaders.set('Authorization', 'Bearer ' + tokens.accessToken)
  }

  const response = NextResponse.next({
    request: { headers: requestHeaders },
  })

  if (tokens) {
    response.cookies.set(createAccessTokenCookie(tokens.accessToken))
    response.cookies.set(createRefreshTokenCookie(tokens.accessToken))
  }

  return response
}


================================================
FILE: apps/nextjs/src/shared/api/auth-api.ts
================================================
import { cookies } from 'next/headers'

import { baseUrl, jsonHeaders } from '@/shared/api/base'

import type {
  AuthTokensResponse,
  MeResponseResponse,
  OAuthLoginArgs,
  RefreshTokensArgs,
} from './authApi.types'

/**
 * Обёртка над fetch, которая проверяет response.ok
 */
async function checkResponse<T>(response: Response): Promise<T> {
  if (!response.ok) {
    const errorBody = await response.text()
    throw new Error(`Request failed with status ${response.status}: ${errorBody}`)
  }
  return (await response.json()) as T
}

export const authApi = {
  // 1) Login → POST /auth/login
  async login(payload: OAuthLoginArgs): Promise<AuthTokensResponse> {
    const response = await fetch(`${baseUrl}/auth/login`, {
      method: 'POST',
      headers: jsonHeaders,
      body: JSON.stringify(payload),
    })
    return checkResponse<AuthTokensResponse>(response)
  },

  // 2) Logout → POST /auth/logout
  async logout(payload: RefreshTokensArgs): Promise<void> {
    const response = await fetch(`${baseUrl}/auth/logout`, {
      method: 'POST',
      headers: jsonHeaders,
      body: JSON.stringify(payload),
    })
    // не ожидаем JSON в ответе
    if (!response.ok) {
      const errorBody = await response.text()
      throw new Error(`Logout failed with status ${response.status}: ${errorBody}`)
    }
  },

  // 3) Получить URL для OAuth-редиректа (без сетевого запроса)
  oauthUrl(redirectUrl: string): string {
    // Здесь предполагается, что authEndpoint — это что-то вроде '/api/auth'

    return `${baseUrl}/auth/oauth-redirect?callbackUrl=${encodeURIComponent(redirectUrl)}`
  },

  // 4) Refresh token → POST /auth/refresh
  async refreshToken(payload: RefreshTokensArgs): Promise<AuthTokensResponse> {
    const response = await fetch(`${baseUrl}/auth/refresh`, {
      method: 'POST',
      headers: jsonHeaders,
      body: JSON.stringify(payload),
    })
    return checkResponse<AuthTokensResponse>(response)
  },

  // 5) Get current user → GET /auth/me
  async getMe(): Promise<MeResponseResponse> {
    const cookieStore = await cookies()
    const token = cookieStore.get('access-token')?.value

    const response = await fetch(`${baseUrl}/auth/me`, {
      method: 'GET',
      headers: {
        ...jsonHeaders,
        Authorization: 'Bearer ' + token,
      },
      // Если нужен авторизационный заголовок — добавьте сюда:
      // headers: {
      //   Authorization: `Bearer ${localStorage.getItem("accessToken")}`,
      // },
    })
    return checkResponse<MeResponseResponse>(response)
  },
}


================================================
FILE: apps/nextjs/src/shared/api/authApi.types.ts
================================================
export type MeResponseResponse = {
  userId: string
  login: string
}

export type AuthTokensResponse = {
  refreshToken: string
  accessToken: string
}

export type RefreshTokensArgs = {
  refreshToken: string
}

export type OAuthLoginArgs = {
  code: string
  redirectUri: string
  accessTokenTTL: string // e.g. "3m"
  rememberMe: boolean
}

export const localStorageKeys = {
  refreshToken: 'musicfun-refresh-token',
  accessToken: 'musicfun-access-token',
}


================================================
FILE: apps/nextjs/src/shared/api/base.ts
================================================
export const baseUrl = process.env.BASE_URL!
export const apiKey = process.env.API_KEY!

export const jsonHeaders = {
  'Content-Type': 'application/json',
  'api-Key': apiKey,
  Origin: 'http://localhost:3000',
}

export const formHeaders = {
  'api-Key': apiKey,
}

export const redirectAfterOauthUri = 'http://localhost:3000/api/oauth/callback'


================================================
FILE: apps/nextjs/src/shared/api/tracks/tracksApi.ts
================================================
import { baseUrl, formHeaders, jsonHeaders } from '@/shared/api/base'
import { Nullable } from '@/shared/common.types'

import type {
  FetchPlaylistsTracksResponse,
  FetchTracksArgs,
  FetchTracksResponse,
  ReactionResponse,
  TrackDetailAttributes,
  TrackDetails,
  UpdateTrackArgs,
} from './tracksApi.types.ts'

export const tracksApi = {
  async fetchTracks({ pageSize = 3, pageNumber, search = '' }: FetchTracksArgs) {
    const url = new URL(`${baseUrl}/playlists/tracks`)
    url.searchParams.set('pageSize', pageSize.toString())
    url.searchParams.set('pageNumber', pageNumber.toString())
    url.searchParams.set('search', search)

    const res = await fetch(url.toString(), { headers: jsonHeaders })
    return res.json() as Promise<FetchTracksResponse>
  },

  async fetchTracksInPlaylist({ playlistId }: { playlistId: string }) {
    const url = `${baseUrl}/playlists/${playlistId}/tracks`
    const res = await fetch(url, { headers: jsonHeaders })
    return res.json() as Promise<FetchPlaylistsTracksResponse>
  },

  async fetchTrackById(trackId: string) {
    const url = `${baseUrl}/playlists/tracks/${trackId}`
    const res = await fetch(url, { headers: jsonHeaders })
    return res.json() as Promise<{ data: TrackDetails<TrackDetailAttributes> }>
  },

  async createTrack({ title, file }: { title: string; file: File }) {
    const formData = new FormData()
    formData.append('title', title)
    formData.append('file', file)

    const url = `${baseUrl}/playlists/tracks/upload`
    const res = await fetch(url, {
      method: 'POST',
      headers: formHeaders,
      body: formData,
    })
    return res.json() as Promise<{ data: TrackDetails<TrackDetailAttributes> }>
  },

  async removeTrack(trackId: string) {
    const url = `${baseUrl}/playlists/tracks/${trackId}`
    await fetch(url, { method: 'DELETE', headers: jsonHeaders })
  },

  // async uploadTrackCover({ trackId, file }: { trackId: string; file: File }) {
  //   const formData = new FormData()
  //   formData.append('cover', file)
  //
  //   const url = `${baseUrl}/playlists/tracks/${trackId}/cover`
  //   const res = await fetch(url, {
  //     method: 'POST',
  //     headers: formHeaders,
  //     body: formData,
  //   })
  //   return res.json() as Promise<Cover>
  // },

  async updateTrack({ trackId, payload }: { trackId: string; payload: UpdateTrackArgs }) {
    const url = `${baseUrl}/playlists/tracks/${trackId}`
    const res = await fetch(url, {
      method: 'PUT',
      headers: jsonHeaders,
      body: JSON.stringify(payload),
    })
    return res.json() as Promise<{ data: TrackDetails<TrackDetailAttributes> }>
  },

  async addTrackToPlaylist({ playlistId, trackId }: { playlistId: string; trackId: string }) {
    const url = `${baseUrl}/playlists/${playlistId}/relationships/tracks`
    await fetch(url, {
      method: 'POST',
      headers: jsonHeaders,
      body: JSON.stringify({ trackId }),
    })
  },

  async removeTrackFromPlaylist({ playlistId, trackId }: { playlistId: string; trackId: string }) {
    const url = `${baseUrl}/playlists/${playlistId}/relationships/tracks/${trackId}`
    await fetch(url, { method: 'DELETE', headers: jsonHeaders })
  },

  async reorderTracks({
    trackId,
    playlistId,
    putAfterItemId,
  }: {
    trackId: string
    playlistId: string
    putAfterItemId: Nullable<string>
  }) {
    const url = `${baseUrl}/playlists/${playlistId}/tracks/${trackId}/reorder`
    await fetch(url, {
      method: 'PUT',
      headers: jsonHeaders,
      body: JSON.stringify({ putAfterItemId }),
    })
  },

  async like(trackId: string) {
    const url = `${baseUrl}/playlists/tracks/${trackId}/like`
    const res = await fetch(url, {
      method: 'POST',
      headers: jsonHeaders,
      body: JSON.stringify({}),
    })
    return res.json() as Promise<ReactionResponse>
  },

  async dislike(trackId: string) {
    const url = `${baseUrl}/playlists/tracks/${trackId}/dislike`
    const res = await fetch(url, {
      method: 'POST',
      headers: jsonHeaders,
      body: JSON.stringify({}),
    })
    return res.json() as Promise<ReactionResponse>
  },
}


================================================
FILE: apps/nextjs/src/shared/api/tracks/tracksApi.types.ts
================================================
import { Meta, Nullable } from '../../common/types/common.types'
import { CurrentUserReaction } from '../../common/types/enums'
import { Images, User } from '../../common/types/playlists-tracks.types'
import { Artist } from '../artists/artistsApi.types'
import { Tag } from '../tags/tagsApi.types'

export type TrackDetails<T> = {
  id: string
  type: 'tracks'
  attributes: T
}

// Attributes
export type BaseAttributes = {
  title: string
  addedAt: string
  attachments: TrackAttachment[]
  images: Images
}

export type FetchTracksAttributes = BaseAttributes & {
  user: User
}

export type TrackDetailAttributes = BaseAttributes & {
  lyrics: Nullable<string>
  releaseDate: Nullable<string>
  updatedAt: string
  duration: number
  processingStatus: TrackProcessingStatus
  visibility: TrackVisibility
  tags: Tag[]
  artists: Artist[]
  // likes
  currentUserReaction: CurrentUserReaction
  dislikesCount: number
  likesCount: number
}

export type PlaylistItemAttributes = BaseAttributes & {
  updatedAt: string
  order: number
}

// Attachment
export type TrackAttachment = {
  id: string
  addedAt: string
  updatedAt: string
  version: number
  url: string
  contentType: string
  originalName: string
  originalKey: string
  fileSize: number
}

// Response
export type FetchTracksResponse = {
  data: TrackDetails<FetchTracksAttributes>[]
  meta: Meta
}

export type FetchPlaylistsTracksResponse = {
  data: TrackDetails<PlaylistItemAttributes>[]
  meta: Meta
}

export type ReactionResponse = {
  objectId: string
  value: number
  likes: number
  dislikes: number
}

// Arguments
export type FetchTracksArgs = {
  pageSize?: number
  pageNumber: number
  search?: string
}

export type UpdateTrackArgs = {
  title?: string
  lyrics?: string
  visibility?: TrackVisibility
  releaseDate?: string
  tagIds?: string[]
  artistsIds?: string[]
}

// Literal types
type TrackVisibility = 'private' | 'public'

type TrackProcessingStatus = 'uploaded' | 'converting' | 'ready'


================================================
FILE: apps/nextjs/src/shared/common.types.ts
================================================
export type Nullable<T> = T | null


================================================
FILE: apps/nextjs/src/shared/utils/cookieHelpers.ts
================================================
// src/shared/utils/cookieHelpers.ts

import { getJwtExpirationMaxAge } from '@/shared/utils/jwt-util'

export interface CookieDef {
  name: string
  value: string
  httpOnly: boolean
  maxAge: number
  path: string
}

/**
 * Возвращает определение cookie для access-token
 */
export function createAccessTokenCookie(token: string): CookieDef {
  return {
    name: 'access-token',
    value: token,
    httpOnly: true,
    maxAge: getJwtExpirationMaxAge(token),
    path: '/',
  }
}

/**
 * Возвращает определение cookie для refresh-token
 */
export function createRefreshTokenCookie(token: string): CookieDef {
  return {
    name: 'refresh-token',
    value: token,
    httpOnly: true,
    maxAge: getJwtExpirationMaxAge(token),
    path: '/',
  }
}


================================================
FILE: apps/nextjs/src/shared/utils/jwt-util.ts
================================================
// src/shared/utils/jwtUtils.ts

/**
 * Распарсить payload JWT и вернуть поле exp
 * @throws Error если формат токена некорректен или нет поля exp
 */
function parseJwtExp(token: string): number {
  const parts = token.split('.')
  if (parts.length !== 3) {
    throw new Error('Invalid JWT format')
  }

  // Декодируем payload (в middle-segment)
  const payloadBase64 = parts[1].replace(/-/g, '+').replace(/_/g, '/')
  const payloadJson = Buffer.from(payloadBase64, 'base64').toString('utf-8')
  const payload = JSON.parse(payloadJson)

  if (typeof payload.exp !== 'number') {
    throw new Error('JWT payload missing exp claim')
  }

  return payload.exp
}

/**
 * Возвращает, сколько секунд осталось до истечения токена
 */
export function getSecondsToExpiration(token: string): number {
  const exp = parseJwtExp(token)
  const now = Math.floor(Date.now() / 1000)
  return exp - now
}

/**
 * Возвращает maxAge для установки в cookie, основанный на exp токена
 * @throws Error если токен уже истёк или exp–now ≤ 0
 */
export function getJwtExpirationMaxAge(token: string): number {
  const seconds = getSecondsToExpiration(token)
  if (seconds <= 0) {
    throw new Error('Token already expired')
  }
  return seconds
}


================================================
FILE: apps/nextjs/tsconfig.json
================================================
{
  "compilerOptions": {
    "target": "ES2017",
    "lib": ["dom", "dom.iterable", "esnext"],
    "allowJs": true,
    "skipLibCheck": true,
    "strict": true,
    "noEmit": true,
    "esModuleInterop": true,
    "module": "esnext",
    "moduleResolution": "bundler",
    "resolveJsonModule": true,
    "isolatedModules": true,
    "jsx": "preserve",
    "incremental": true,
    "plugins": [
      {
        "name": "next"
      }
    ],
    "paths": {
      "@/*": ["./src/*"]
    }
  },
  "include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", ".next/types/**/*.ts"],
  "exclude": ["node_modules"]
}


================================================
FILE: apps/react-effector-fsd/.gitignore
================================================
# Logs
logs
*.log
npm-debug.log*
yarn-debug.log*
yarn-error.log*
pnpm-debug.log*
lerna-debug.log*

node_modules
dist
dist-ssr
*.local

# Editor directories and files
.vscode/*
!.vscode/extensions.json
.idea
.DS_Store
*.suo
*.ntvs*
*.njsproj
*.sln
*.sw?
.DS_Store
.env
/node_modules/

# React Router
/.react-router/
/build/


================================================
FILE: apps/react-effector-fsd/README.md
================================================
# Welcome to React Router!

A modern, production-ready template for building full-stack React applications using React Router.

[![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/remix-run/react-router-templates/tree/main/default)

## Features

- 🚀 Server-side rendering
- ⚡️ Hot Module Replacement (HMR)
- 📦 Asset bundling and optimization
- 🔄 Data loading and mutations
- 🔒 TypeScript by default
- 🎉 TailwindCSS for styling
- 📖 [React Router docs](https://reactrouter.com/)

## Getting Started

### Installation

Install the dependencies:

```bash
npm install
```

### Development

Start the development server with HMR:

```bash
npm run dev
```

Your application will be available at `http://localhost:5173`.

## Building for Production

Create a production build:

```bash
npm run build
```

## Deployment

### Docker Deployment

To build and run using Docker:

```bash
docker build -t my-app .

# Run the container
docker run -p 3000:3000 my-app
```

The containerized application can be deployed to any platform that supports Docker, including:

- AWS ECS
- Google Cloud Run
- Azure Container Apps
- Digital Ocean App Platform
- Fly.io
- Railway

### DIY Deployment

If you're familiar with deploying Node applications, the built-in app server is production-ready.

Make sure to deploy the output of `npm run build`

```
├── package.json
├── package-lock.json (or pnpm-lock.yaml, or bun.lockb)
├── build/
│   ├── client/    # Static assets
│   └── server/    # Server-side code
```

## Styling

This template comes with [Tailwind CSS](https://tailwindcss.com/) already configured for a simple default starting experience. You can use whatever CSS framework you prefer.

---

Built with ❤️ using React Router.


================================================
FILE: apps/react-effector-fsd/eslint.config.js
================================================
import js from '@eslint/js'
import { defineConfig, globalIgnores } from 'eslint/config'
import reactHooks from 'eslint-plugin-react-hooks'
import reactRefresh from 'eslint-plugin-react-refresh'
import globals from 'globals'
import tseslint from 'typescript-eslint'

export default defineConfig([
  globalIgnores(['dist']),
  {
    files: ['**/*.{ts,tsx}'],
    extends: [
      js.configs.recommended,
      tseslint.configs.recommended,
      reactHooks.configs['recommended-latest'],
      reactRefresh.configs.vite,
    ],
    languageOptions: {
      ecmaVersion: 2020,
      globals: globals.browser,
    },
  },
])


================================================
FILE: apps/react-effector-fsd/index.html
================================================
<!doctype html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <link rel="icon" type="image/svg+xml" href="/favicon.svg" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Musicfun Effector</title>
    <!-- SPA redirect handler for GitHub Pages -->
    <script>
      ;(function () {
        var redirect = sessionStorage.redirect
        delete sessionStorage.redirect
        if (redirect && redirect !== location.href) {
          history.replaceState(null, null, redirect)
        }

        // Check for spa_redirect query parameter
        var searchParams = new URLSearchParams(window.location.search)
        var spaRedirect = searchParams.get('spa_redirect')
        if (spaRedirect) {
          searchParams.delete('spa_redirect')
          var newSearch = searchParams.toString()
          var newUrl = decodeURIComponent(spaRedirect)
          sessionStorage.redirect = newUrl
          window.location.replace(window.location.pathname + (newSearch ? '?' + newSearch : ''))
        }
      })()
    </script>
  </head>
  <body>
    <div id="root"></div>
    <script type="module" src="/src/app/main.tsx"></script>
  </body>
</html>


================================================
FILE: apps/react-effector-fsd/package.json
================================================
{
  "name": "react-effector-fsd",
  "private": true,
  "version": "0.0.1",
  "type": "module",
  "scripts": {
    "dev": "vite",
    "build": "tsc -b && vite build",
    "lint": "eslint .",
    "preview": "vite preview",
    "start": "vite ./build/server/index.js",
    "typecheck": "tsc --watch",
    "generate:api": "pnpm openapi-typescript https://musicfun.it-incubator.app/api-json -o ./src/shared/api/schema.ts --root-types --enum --enum-values --dedupe-enums"
  },
  "dependencies": {
    "@react-router/node": "^7.9.4",
    "@react-router/serve": "^7.9.4",
    "clsx": "^2.1.1",
    "effector": "^23.4.4",
    "effector-react": "^23.3.0",
    "isbot": "^5.1.31",
    "openapi-fetch": "^0.14.1",
    "react": "^19.2.0",
    "react-dom": "^19.2.0",
    "react-router": "^7.9.4",
    "react-toastify": "^11.0.5"
  },
  "devDependencies": {
    "@react-router/dev": "^7.9.4",
    "@storybook/react-vite": "^9.1.13",
    "@tailwindcss/vite": "^4.1.14",
    "@types/node": "^24.7.2",
    "@types/react": "^19.2.2",
    "@types/react-dom": "^19.2.1",
    "@vitejs/plugin-react": "^5.0.4",
    "babel-plugin-react-compiler": "^1.0.0",
    "openapi-typescript": "^7.9.1",
    "tailwindcss": "^4.1.14",
    "typescript": "^5.9.3",
    "vite": "npm:rolldown-vite@7.1.16",
    "vite-tsconfig-paths": "^5.1.4"
  },
  "overrides": {
    "vite": "npm:rolldown-vite@7.1.16"
  }
}


================================================
FILE: apps/react-effector-fsd/src/app/App.tsx
================================================
import '@/app/styles/fonts.css'
import '@/app/styles/variables.css'
import '@/app/styles/reset.css'
import '@/app/styles/global.css'

import { useEffect } from 'react'
import { ToastContainer } from 'react-toastify'

import { appStarted } from './model/init.ts'
import { Routing } from './routes'

export default function App() {
  useEffect(() => {
    appStarted()
  }, [])

  return (
    <>
      <Routing />
      <ToastContainer />
    </>
  )
}


================================================
FILE: apps/react-effector-fsd/src/app/main.tsx
================================================
import '@/app/styles/fonts.css'
import '@/app/styles/variables.css'
import '@/app/styles/reset.css'
import '@/app/styles/global.css'
import 'react-toastify/dist/ReactToastify.css'

import { StrictMode } from 'react'
import { createRoot } from 'react-dom/client'
import { BrowserRouter } from 'react-router'

import App from './App.tsx'

createRoot(document.getElementById('root')!).render(
  <StrictMode>
    <BrowserRouter basename="/effector">
      <App />
    </BrowserRouter>
  </StrictMode>
)


================================================
FILE: apps/react-effector-fsd/src/app/model/init.ts
================================================
import { createEvent, sample } from 'effector'

import { initApiClientFx } from '@/features/auth/model/model.ts'

export const appStarted = createEvent()

sample({
  clock: appStarted,
  target: initApiClientFx,
})


================================================
FILE: apps/react-effector-fsd/src/app/routes/Routing.tsx
================================================
import { Route, Routes } from 'react-router'

import { OAuthCallback } from '@/pages/auth/OAuthRedirect/OAuthCallback.tsx'
import { Home } from '@/pages/home'
import { UserPage } from '@/pages/user'
import { Layout } from '@/widgets/layout'

export const Routing = () => (
  <Routes>
    <Route path="/oauth/callback" element={<OAuthCallback />} />
    <Route path="/" element={<Layout />}>
      <Route index element={<Home />} />

      {/*<Route path="/tracks" element={<TracksPage />} />*/}
      {/*<Route path="/tracks/:id" element={<TrackPage />} />*/}

      {/*<Route path="/playlists" element={<PlaylistsPage />} />*/}
      {/*<Route path="/playlists/:id" element={<PlaylistPage />} />*/}

      <Route path="/user/:id" element={<UserPage />} />
    </Route>
  </Routes>
)


================================================
FILE: apps/react-effector-fsd/src/app/routes/index.ts
================================================
export { Routing } from './Routing'


================================================
FILE: apps/react-effector-fsd/src/app/styles/fonts.css
================================================
/*
  source: https://gwfh.mranftl.com/fonts/lato?subsets=latin
*/

/* lato-regular - latin */
@font-face {
  font-family: Lato;
  font-weight: 400;
  font-style: normal;
  font-display: swap; /* Check https://developer.mozilla.org/en-US/docs/Web/CSS/@font-face/font-display for other options. */
  src: url('../../shared/fonts/lato-v24-latin-regular.woff2') format('woff2'); /* Chrome 36+, Opera 23+, Firefox 39+, Safari 12+, iOS 10+ */
}

/* lato-700 - latin */
@font-face {
  font-family: Lato;
  font-weight: 700;
  font-style: normal;
  font-display: swap; /* Check https://developer.mozilla.org/en-US/docs/Web/CSS/@font-face/font-display for other options. */
  src: url('../../shared/fonts/lato-v24-latin-700.woff2') format('woff2'); /* Chrome 36+, Opera 23+, Firefox 39+, Safari 12+, iOS 10+ */
}

/* lato-900 - latin */
@font-face {
  font-family: Lato;
  font-weight: 900;
  font-style: normal;
  font-display: swap; /* Check https://developer.mozilla.org/en-US/docs/Web/CSS/@font-face/font-display for other options. */
  src: url('../../shared/fonts/lato-v24-latin-900.woff2') format('woff2'); /* Chrome 36+, Opera 23+, Firefox 39+, Safari 12+, iOS 10+ */
}


================================================
FILE: apps/react-effector-fsd/src/app/styles/global.css
================================================
:root {
  font-family: Lato, sans-serif;
  font-weight: 400;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  line-height: 100%;
  text-rendering: optimizelegibility;

  font-synthesis: none;
}

/* Scrollbar styles */
* {
  scrollbar-color: var(--color-bg-secondary) var(--color-bg-primary);
  scrollbar-width: thin;
}

body {
  margin: 0;
  color: var(--color-text-primary);
  background-color: var(--color-bg-primary);
}


================================================
FILE: apps/react-effector-fsd/src/app/styles/reset.css
================================================
/* Modern CSS Reset: https://piccalil.li/blog/a-more-modern-css-reset */

/* Box sizing rules */
*,
*::before,
*::after {
  box-sizing: border-box;
}

/* Prevent font size inflation */
html {
  text-size-adjust: none;
}

/* Remove default margin in favour of better control in authored CSS */
body,
h1,
h2,
h3,
h4,
p,
figure,
blockquote,
dl,
dd {
  margin-block-end: 0;
}

ul,
ol {
  margin: 0;
  padding: 0;
  list-style: none;
}

/* Set core body defaults */
body {
  min-height: 100vh;
  line-height: 1.5;
}

/* Set shorter line heights on headings and interactive elements */
h1,
h2,
h3,
h4,
button,
input,
label {
  border: none;
  line-height: 1.1;
}

/* Balance text wrapping on headings */
h1,
h2,
h3,
h4 {
  text-wrap: balance;
}

/* A elements that don't have a class get default styles */
a {
  color: currentcolor;
  text-decoration: none;
}

/* Make images easier to work with */
img,
picture {
  display: block;
  max-width: 100%;
}

/* Inherit fonts for inputs and buttons */
input,
button,
textarea,
select {
  font-family: inherit;
  font-size: inherit;
}

/* Anything that has been anchored to should have extra scroll margin */
:target {
  scroll-margin-block: 5ex;
}


================================================
FILE: apps/react-effector-fsd/src/app/styles/variables.css
================================================
:root {
  /*
  * Colors
  */
  --color-accent: #ff38b6;
  --color-disabled: #858585;
  --color-outline-focus: #1a75f5;

  /* Text */
  --color-text-primary: #fff;
  --color-text-primary-reverse: #000;
  --color-text-secondary: #b3b3b3;
  --color-text-label: #808080;
  --color-text-error: #f51a51;

  /* Backgrounds */
  --color-bg-primary: #000;
  --color-bg-secondary: #141414;
  --color-bg-primary-reverse: #fff;
  --color-bg-input-hover: #262626;
  --color-bg-card: rgb(7 7 7 / 50%);
  --color-bg-interactive-secondary: #333;

  /* Borders */
  --color-border-base: #7f7f7f;
  --color-border-input-primary: #4d4d4d;
  --color-border-input-active: #fffefe;

  /*
  * Typography
  */

  /* font-sizes */
  --font-size-xxxs: 12px;
  --font-size-xxs: 13px;
  --font-size-xs: 14px;
  --font-size-s: 16px;
  --font-size-m: 18px;
  --font-size-l: 20px;
  --font-size-xl: 24px;
  --font-size-xxl: 30px;
  --font-size-xxxl: 60px;

  /*
  * Layout
  */
  --header-height: 80px;
  --player-height: 112px;
}


================================================
FILE: apps/react-effector-fsd/src/features/auth/api/login.ts
================================================
import { api } from '@/shared/api/client'

import type { LoginRequestPayload, RefreshOutput } from '../model/auth-api.types'

export const loginApi = async (payload: LoginRequestPayload): Promise<RefreshOutput> => {
  const res = await api().POST('/auth/login', {
    body: payload,
  })

  if (res.error) {
    throw new Error(res.error?.message)
  }

  return res.data
}


================================================
FILE: apps/react-effector-fsd/src/features/auth/api/logout.ts
================================================
import { api } from '@/shared/api/client'

export const logoutApi = async (refreshToken: string) => {
  await api().POST('/auth/logout', {
    body: { refreshToken },
  })
}


================================================
FILE: apps/react-effector-fsd/src/features/auth/api/me.ts
================================================
import { api } from '@/shared/api/client'

import type { User } from '../model/user.types'

export const meApi = async (): Promise<User> => {
  const res = await api().GET('/auth/me')
  return res.data ?? null
}


================================================
FILE: apps/react-effector-fsd/src/features/auth/index.ts
================================================
export { getOauthRedirectUrl } from './model/auth-api.types'
export { $me, loginFx, logoutFx } from './model/model.ts'
export * from './ui'


================================================
FILE: apps/react-effector-fsd/src/features/auth/model/auth-api.types.ts
================================================
import { getClientConfig } from '@/shared/api/client.ts'
import type { components } from '@/shared/api/schema.ts'

export type RefreshOutput = components['schemas']['RefreshOutput']
export type RefreshRequestPayload = components['schemas']['RefreshRequestPayload']
export type LoginRequestPayload = components['schemas']['LoginRequestPayload']

export const localStorageKeys = {
  refreshToken: 'spotifun-refresh-token',
  accessToken: 'spotifun-access-token',
}

export const getOauthRedirectUrl = (redirectUrl: string) =>
  getClientConfig().baseURL + `/auth/oauth-redirect?callbackUrl=${redirectUrl}`


================================================
FILE: apps/react-effector-fsd/src/features/auth/model/model.ts
================================================
import { createEffect, createStore, sample } from 'effector'
import { toast } from 'react-toastify'

import { setClientConfig } from '@/shared/api/client.ts'
import { API_BASE_URL, API_KEY } from '@/shared/config/config.ts'

import { loginApi } from '../api/login'
import { logoutApi } from '../api/logout'
import { meApi } from '../api/me'
import { localStorageKeys, type LoginRequestPayload, type RefreshOutput } from './auth-api.types'
import type { User } from './user.types'

export const initApiClientFx = createEffect(() => {
  setClientConfig({
    baseURL: API_BASE_URL,
    apiKey: API_KEY,
    getAccessToken: async () => localStorage.getItem(localStorageKeys.accessToken),
    getRefreshToken: async () => localStorage.getItem(localStorageKeys.refreshToken),
    saveAccessToken: async (token) =>
      token
        ? localStorage.setItem(localStorageKeys.accessToken, token)
        : localStorage.removeItem(localStorageKeys.accessToken),
    saveRefreshToken: async (token) =>
      token
        ? localStorage.setItem(localStorageKeys.refreshToken, token)
        : localStorage.removeItem(localStorageKeys.refreshToken),

    toManyRequestsErrorHandler: (message: string | null) => {
      toast(message)
    },
    logoutHandler: () => {},
  })
})

export const fetchMeFx = createEffect<void, User>(meApi)
export const loginFx = createEffect<LoginRequestPayload, RefreshOutput>(loginApi)
export const logoutFx = createEffect(async () => {
  const refreshToken = localStorage.getItem(localStorageKeys.refreshToken)!
  await logoutApi(refreshToken)
})

const saveTokensFx = createEffect((data: RefreshOutput) => {
  localStorage.setItem(localStorageKeys.refreshToken, data.refreshToken)
  localStorage.setItem(localStorageKeys.accessToken, data.accessToken)
})
const clearTokensFx = createEffect(() => {
  localStorage.removeItem(localStorageKeys.accessToken)
  localStorage.removeItem(localStorageKeys.refreshToken)
})

export const $me = createStore<User>(null)
  .on(fetchMeFx.doneData, (_, me) => me)
  .reset(logoutFx.done)

export const $isAuthorized = createStore<boolean>(false)
  .on(fetchMeFx.doneData, (_, me) => Boolean(me))
  .reset(logoutFx.done)

sample({
  clock: initApiClientFx.done,
  filter: () => Boolean(localStorage.getItem(localStorageKeys.accessToken)),
  target: fetchMeFx,
})

sample({
  clock: loginFx.doneData,
  target: saveTokensFx,
})
sample({
  clock: saveTokensFx.done,
  target: fetchMeFx,
})

sample({
  clock: logoutFx.done,
  target: clearTokensFx,
})


================================================
FILE: apps/react-effector-fsd/src/features/auth/model/user.types.ts
================================================
import type { components } from '@/shared/api/schema.ts'

export type User = components['schemas']['GetMeOutput'] | null


================================================
FILE: apps/react-effector-fsd/src/features/auth/ui/LoginButtonAndModal/LoginButtonAndModal.module.css
================================================
.dialog {
  width: 376px;
  padding-bottom: 22px;
}

.content {
  display: flex;
  flex-direction: column;
  gap: 32px;
  align-items: center;

  text-align: center;
}

.icon {
  display: flex;
  align-items: center;
  justify-content: center;

  width: 60px;
  height: 60px;
  border-radius: 50%;

  font-size: 24px;

  background-color: var(--color-accent);
}

.button {
  height: 55px;
}

.secondary {
  background-color: #555;
}


================================================
FILE: apps/react-effector-fsd/src/features/auth/ui/LoginButtonAndModal/LoginButtonAndModal.tsx
================================================
import clsx from 'clsx'
import { useUnit } from 'effector-react'
import { useState } from 'react'

import { getOauthRedirectUrl, loginFx } from '@/features/auth'
import { Button } from '@/shared/components/Button'
import { Dialog, DialogContent, DialogHeader } from '@/shared/components/Dialog'
import { Typography } from '@/shared/components/Typography'
import { CURRENT_APP_DOMAIN } from '@/shared/config/config'

import s from './LoginButtonAndModal.module.css'

export const LoginButtonAndModal = () => {
  const [isOpen, setIsOpen] = useState(false)
  const [login, loginPending] = useUnit([loginFx, loginFx.pending])

  const handleOpenModal = () => setIsOpen(true)
  const handleCloseModal = () => setIsOpen(false)

  const loginHandler = () => {
    const redirectUri = window.location.origin + CURRENT_APP_DOMAIN + 'oauth/callback' // todo: to config
    const url = getOauthRedirectUrl(redirectUri)
    window.open(url, 'oauthPopup', 'width=500,height=600')

    const receiveMessage = async (event: MessageEvent) => {
      if (event.origin !== window.location.origin) {
        // todo: to config
        return
      }

      const { code } = event.data
      if (code) {
        console.log('✅ code received:', code)
        window.removeEventListener('message', receiveMessage)

        // effector login
        login({ code, accessTokenTTL: '10m', redirectUri, rememberMe: true })
        handleCloseModal()
      }
    }

    window.addEventListener('message', receiveMessage)
  }

  return (
    <>
      <Button variant="primary" onClick={handleOpenModal}>
        Sign in
      </Button>

      <Dialog open={isOpen} onClose={handleCloseModal} className={s.dialog}>
        <DialogHeader />

        <DialogContent className={s.content}>
          <Typography variant="h2">
            Millions of Songs. <br /> Free on Musicfun.
          </Typography>

          <div className={s.icon}>😊</div>

          <Button className={clsx(s.button, s.secondary)} fullWidth onClick={handleCloseModal}>
            Continue without Sign in
          </Button>
          <Button
            as="button"
            target="_blank"
            className={s.button}
            variant="primary"
            fullWidth
            onClick={loginHandler}
            disabled={loginPending}>
            {loginPending ? 'Signing in...' : 'Sign in with APIHub'}
          </Button>
        </DialogContent>
      </Dialog>
    </>
  )
}


================================================
FILE: apps/react-effector-fsd/src/features/auth/ui/LoginButtonAndModal/index.ts
================================================
export { LoginButtonAndModal } from './LoginButtonAndModal'


================================================
FILE: apps/react-effector-fsd/src/features/auth/ui/ProfileDropdownMenu/ProfileDropdownMenu.module.css
================================================
.trigger {
  cursor: pointer;
  display: flex;
  gap: 8px;
  align-items: center;
}

.avatar {
  overflow: hidden;
  width: 34px;
  height: 34px;
  border-radius: 50%;
}

.name {
  color: var(--color-text-primary);
}


================================================
FILE: apps/react-effector-fsd/src/features/auth/ui/ProfileDropdownMenu/ProfileDropdownMenu.stories.tsx
================================================
import type { Meta, StoryObj } from '@storybook/react-vite'

import { ProfileDropdownMenu } from './ProfileDropdownMenu'

const meta: Meta<typeof ProfileDropdownMenu> = {
  title: 'entities/ProfileDropdownMenu',
  component: ProfileDropdownMenu,
  parameters: {
    layout: 'centered',
  },
}

export default meta

type Story = StoryObj<typeof ProfileDropdownMenu>

export const Default: Story = {
  args: {
    avatar: 'https://unsplash.it/182/182',
  },
}


================================================
FILE: apps/react-effector-fsd/src/features/auth/ui/ProfileDropdownMenu/ProfileDropdownMenu.tsx
================================================
import { useUnit } from 'effector-react'
import { Link } from 'react-router'

import { $me, logoutFx } from '@/features/auth'
import {
  DropdownMenu,
  DropdownMenuContent,
  DropdownMenuItem,
  DropdownMenuTrigger,
  Typography,
} from '@/shared/components'
import { LogoutIcon, ProfileIcon } from '@/shared/icons'

import s from './ProfileDropdownMenu.module.css'

export const ProfileDropdownMenu = ({ avatar }: { avatar: string }) => {
  const [me, logout, logoutPending] = useUnit([$me, logoutFx, logoutFx.pending])

  const handleLogout = () => {
    logout()
  }

  return (
    <DropdownMenu>
      <DropdownMenuTrigger asChild className={s.trigger}>
        <div className={s.avatar}>
          <img src={avatar} alt={''} />
        </div>
        <Typography className={s.name} variant="body2">
          {me?.login ?? 'anonymous'}
        </Typography>
      </DropdownMenuTrigger>
      <DropdownMenuContent align="end">
        <DropdownMenuItem as={Link} to={`/user/${me!.userId}`}>
          <ProfileIcon />
          <span>My Profile</span>
        </DropdownMenuItem>
        <DropdownMenuItem onClick={handleLogout} disabled={logoutPending}>
          <LogoutIcon />
          <span>{logoutPending ? 'Logging out...' : 'Logout'}</span>
        </DropdownMenuItem>
      </DropdownMenuContent>
    </DropdownMenu>
  )
}


================================================
FILE: apps/react-effector-fsd/src/features/auth/ui/ProfileDropdownMenu/index.ts
================================================
export * from './ProfileDropdownMenu'


================================================
FILE: apps/react-effector-fsd/src/features/auth/ui/index.ts
================================================
export * from './LoginButtonAndModal'
export * from './ProfileDropdownMenu'


================================================
FILE: apps/react-effector-fsd/src/pages/auth/OAuthRedirect/OAuthCallback.module.css
================================================
.title {
  text-align: center;
  font-size: 250px;
  margin: 0;
}

.subtitle {
  text-align: center;
  font-size: 50px;
  margin: 0;
  text-transform: uppercase;
}


================================================
FILE: apps/react-effector-fsd/src/pages/auth/OAuthRedirect/OAuthCallback.tsx
================================================
import { useEffect } from 'react'

export const OAuthCallback = () => {
  useEffect(() => {
    const url = new URL(window.location.href)
    const code = url.searchParams.get('code') // или code/state, если flow другой

    if (code && window.opener) {
      window.opener.postMessage({ code }, '*') // Лучше заменить "*" на точный origin
    }

    window.close()
  }, [])

  return <p>Welcome...</p>
}


================================================
FILE: apps/react-effector-fsd/src/pages/home/Home.tsx
================================================
export function Home() {
  return <div>Musicfun home page</div>
}


================================================
FILE: apps/react-effector-fsd/src/pages/home/index.ts
================================================
export { Home } from './Home'


================================================
FILE: apps/react-effector-fsd/src/pages/user/UserPage.tsx
================================================
export const UserPage = () => {
  return (
    <main>
      <div>UserPage</div>
    </main>
  )
}


================================================
FILE: apps/react-effector-fsd/src/pages/user/index.ts
================================================
export { UserPage } from './UserPage'


================================================
FILE: apps/react-effector-fsd/src/shared/api/client.ts
================================================
import createClient, { type Middleware } from 'openapi-fetch'

import type { paths } from './schema.ts'

const config = {
  baseURL: null as string | null,
  apiKey: null as string | null,
  getAccessToken: null as (() => Promise<string | null>) | null,
  saveAccessToken: null as ((accessToken: string | null) => Promise<void>) | null,
  getRefreshToken: null as (() => Promise<string | null>) | null,
  saveRefreshToken: null as ((refreshToken: string | null) => Promise<void>) | null,
  toManyRequestsErrorHandler: null as ((message: string | null) => void) | null,
  logoutHandler: null as (() => void) | null,
}

export const setClientConfig = (newConfig: Partial<typeof config>) => {
  Object.assign(config, newConfig)
  _client = undefined // пере-инициализируем
}

export const getClientConfig = () => ({ ...config })

/* ------------------------------------------------------------------ */
/* 2.  Mutex для refresh-а                                             */
/* ------------------------------------------------------------------ */
let refreshPromise: Promise<string> | null = null

export function makeRefreshToken(): Promise<string> {
  if (!refreshPromise) {
    // 1) создаём «замок» сразу
    refreshPromise = (async (): Promise<string> => {
      const refreshToken = await config.getRefreshToken!()
      if (!refreshToken) throw new Error('No refresh token')

      const res = await fetch(`${config.baseURL}/auth/refresh`, {
        method: 'POST',
        headers: {
          'Content-Type': 'application/json',
          'API-KEY': config.apiKey!,
        },
        body: JSON.stringify({ refreshToken }),
      })
      if (res.status !== 201) throw new Error('Refresh failed')

      const { accessToken, refreshToken: newRT } = await res.json()
      await config.saveAccessToken!(accessToken)
      await config.saveRefreshToken!(newRT)

      return accessToken
    })().finally(() => {
      refreshPromise = null // 2) снимаем «замок»
    })
  }

  return refreshPromise
}

const authMiddleware: Middleware = {
  /* ---------- REQUEST -------------------------------------------------- */
  async onRequest({ request }) {
    request.headers.set('API-KEY', config.apiKey!)

    const token = await config.getAccessToken?.()
    if (token) request.headers.set('Authorization', `Bearer ${token}`)
    ;(request as any)._retryClone = request.clone()

    return request
  },
  async onResponse({ request, response }) {
    const req = request as Request & { _retry: boolean }

    if (response.status === 429) {
      const { message } = await response.clone().json()
      config.toManyRequestsErrorHandler?.(message)
    }

    if (response.status !== 401 || request.url.includes('/auth/refresh')) {
      return response // всё ок
    }

    // уже пытались? -> отдаём 401 наружу, чтобы не зациклиться
    if (req._retry) return response
    req._retry = true

    try {
      const newToken = await makeRefreshToken()

      // повторяем исходный запрос с новым токеном
      const orig = (req as any)._retryClone as Request // клон с целым body
      const retry = new Request(orig, { headers: new Headers(orig.headers) })
      retry.headers.set('Authorization', `Bearer ${newToken}`)
      return await fetch(retry)
    } catch (error) {
      console.log(error)
      // refresh не удался → чистим хранилище, отдаём 401
      await config.saveAccessToken!(null)
      await config.saveRefreshToken!(null)
      await config.logoutHandler?.()
      return response
    }
  },
}

let _client: ReturnType<typeof createClient<paths>> | undefined

const LOCAL_HOSTNAMES = new Set(['localhost', '127.0.0.1', '::1', '0.0.0.0'])

function isLocalClient(): boolean {
  if (typeof window === 'undefined') return false // не клиент
  const h = window.location.hostname
  return LOCAL_HOSTNAMES.has(h) || h.endsWith('.localhost')
}

export function assertApiConfig() {
  if (!config.baseURL) {
    const msg = 'baseURL is required. Call setClientConfig({ baseURL })'
    console.error(msg)
    throw new Error(msg)
  }
  if (isLocalClient() && !config.apiKey) {
    const msg =
      'apiKey is required when running client on localhost. Call setClientConfig({ apiKey })'
    console.error(msg)
    throw new Error(msg)
  }
}

export const api = () => {
  if (_client) return _client

  assertApiConfig()

  const client = createClient<paths>({ baseUrl: config.baseURL! })
  client.use(authMiddleware)
  _client = client
  return _client
}


================================================
FILE: apps/react-effector-fsd/src/shared/api/schema.ts
================================================
/**
 * This file was auto-generated by openapi-typescript.
 * Do not make direct changes to the file.
 */

export interface paths {
  '/playlists/my': {
    parameters: {
      query?: never
      header?: never
      path?: never
      cookie?: never
    }
    /**
     * Get my playlists
     * @deprecated
     */
    get: operations['PlaylistsController_getMyPlaylists']
    put?: never
    post?: never
    delete?: never
    options?: never
    head?: never
    patch?: never
    trace?: never
  }
  '/playlists': {
    parameters: {
      query?: never
      header?: never
      path?: never
      cookie?: never
    }
    /**
     * Retrieve all playlists
     * @description Query parameters must conform to the **GetPlaylistsRequestPayload** schema.
     */
    get: operations['PlaylistsPublicController_getPlaylists']
    put?: never
    /** Create a new playlist */
    post: operations['PlaylistsController_createPlaylist']
    delete?: never
    options?: never
    head?: never
    patch?: never
    trace?: never
  }
  '/playlists/{playlistId}': {
    parameters: {
      query?: never
      header?: never
      path?: never
      cookie?: never
    }
    /** Get a single playlist by ID */
    get: operations['PlaylistsPublicController_getPlaylistById']
    /** Update a playlist */
    put: operations['PlaylistsController_updatePlaylist']
    post?: never
    /** Delete a playlist */
    delete: operations['PlaylistsController_deletePlaylist']
    options?: never
    head?: never
    patch?: never
    trace?: never
  }
  '/playlists/{playlistId}/reorder': {
    parameters: {
      query?: never
      header?: never
      path?: never
      cookie?: never
    }
    get?: never
    /** Reorder playlists */
    put: operations['PlaylistsController_reorderPlaylist']
    post?: never
    delete?: never
    options?: never
    head?: never
    patch?: never
    trace?: never
  }
  '/playlists/{playlistId}/images/main': {
    parameters: {
      query?: never
      header?: never
      path?: never
      cookie?: never
    }
    get?: never
    put?: never
    /**
     * Upload playlist cover
     * @description Minimum height — 500px; image must be square
     */
    post: operations['PlaylistsController_uploadMainImage']
    /** Delete playlist cover */
    delete: operations['PlaylistsController_deleteTrackCover']
    options?: never
    head?: never
    patch?: never
    trace?: never
  }
  '/playlists/tracks': {
    parameters: {
      query?: never
      header?: never
      path?: never
      cookie?: never
    }
    /**
     * Get list of all tracks in all playlists.
     * @description Query-parameters schema → [`GetTracksRequestPayload`](#model-GetTracksRequestPayload)
     */
    get: operations['TracksPublicController_getAllTracks']
    put?: never
    post?: never
    delete?: never
    options?: never
    head?: never
    patch?: never
    trace?: never
  }
  '/playlists/{playlistId}/tracks': {
    parameters: {
      query?: never
      header?: never
      path?: never
      cookie?: never
    }
    /** Get list of tracks in a playlist */
    get: operations['TracksPublicController_getPlaylistTracks']
    put?: never
    post?: never
    delete?: never
    options?: never
    head?: never
    patch?: never
    trace?: never
  }
  '/playlists/tracks/{trackId}': {
    parameters: {
      query?: never
      header?: never
      path?: never
      cookie?: never
    }
    /** Get track details by ID */
    get: operations['TracksPublicController_getTrackDetails']
    /** Update track information */
    put: operations['TracksController_updateTrack']
    post?: never
    /** Permanently delete a track */
    delete: operations['TracksController_deleteTrackCompletely']
    options?: never
    head?: never
    patch?: never
    trace?: never
  }
  '/playlists/tracks/{trackId}/likes': {
    parameters: {
      query?: never
      header?: never
      path?: never
      cookie?: never
    }
    get?: never
    put?: never
    /** Like or toggle like on a track */
    post: operations['TracksPublicController_likeTrack']
    delete?: never
    options?: never
    head?: never
    patch?: never
    trace?: never
  }
  '/playlists/tracks/{trackId}/dislikes': {
    parameters: {
      query?: never
      header?: never
      path?: never
      cookie?: never
    }
    get?: never
    put?: never
    /** Dislike or toggle dislike on a track */
    post: operations['TracksPublicController_dislikeTrack']
    delete?: never
    options?: never
    head?: never
    patch?: never
    trace?: never
  }
  '/playlists/tracks/{trackId}/reactions': {
    parameters: {
      query?: never
      header?: never
      path?: never
      cookie?: never
    }
    get?: never
    put?: never
    post?: never
    /** Remove user reaction from a track */
    delete: operations['TracksPublicController_removeTrackReaction']
    options?: never
    head?: never
    patch?: never
    trace?: never
  }
  '/playlists/{playlistId}/likes': {
    parameters: {
      query?: never
      header?: never
      path?: never
      cookie?: never
    }
    get?: never
    put?: never
    /** Like a playlist */
    post: operations['PlaylistsPublicController_likePlaylist']
    delete?: never
    options?: never
    head?: never
    patch?: never
    trace?: never
  }
  '/playlists/{playlistId}/dislikes': {
    parameters: {
      query?: never
      header?: never
      path?: never
      cookie?: never
    }
    get?: never
    put?: never
    /** Dislike a playlist */
    post: operations['PlaylistsPublicController_dislikePlaylist']
    delete?: never
    options?: never
    head?: never
    patch?: never
    trace?: never
  }
  '/playlists/{playlistId}/reactions': {
    parameters: {
      query?: never
      header?: never
      path?: never
      cookie?: never
    }
    get?: never
    put?: never
    post?: never
    /** Remove user reaction from a playlist */
    delete: operations['PlaylistsPublicController_removePlaylistReaction']
    options?: never
    head?: never
    patch?: never
    trace?: never
  }
  '/playlists/{playlistId}/tracks/{trackId}/reorder': {
    parameters: {
      query?: never
      header?: never
      path?: never
      cookie?: never
    }
    get?: never
    /** Reorder tracks in a playlist */
    put: operations['TracksController_reorderTrack']
    post?: never
    delete?: never
    options?: never
    head?: never
    patch?: never
    trace?: never
  }
  '/playlists/{playlistId}/relationships/tracks': {
    parameters: {
      query?: never
      header?: never
      path?: never
      cookie?: never
    }
    get?: never
    put?: never
    /** Add a track to your playlist */
    post: operations['TracksController_addTrackToPlaylist']
    delete?: never
    options?: never
    head?: never
    patch?: never
    trace?: never
  }
  '/playlists/{playlistId}/relationships/tracks/{trackId}': {
    parameters: {
      query?: never
      header?: never
      path?: never
      cookie?: never
    }
    get?: never
    put?: never
    post?: never
    /** Remove a track from your playlist */
    delete: operations['TracksController_unbindTrackFromPlaylist']
    options?: never
    head?: never
    patch?: never
    trace?: never
  }
  '/playlists/tracks/{trackId}/actions/publish': {
    parameters: {
      query?: never
      header?: never
      path?: never
      cookie?: never
    }
    get?: never
    put?: never
    /** Publish a track (make it publicly available) */
    post: operations['TracksController_publishTrack']
    delete?: never
    options?: never
    head?: never
    patch?: never
    trace?: never
  }
  '/playlists/tracks/{trackId}/cover': {
    parameters: {
      query?: never
      header?: never
      path?: never
      cookie?: never
    }
    get?: never
    put?: never
    /** Upload track cover */
    post: operations['TracksController_uploadTrackCover']
    /** Delete track cover */
    delete: operations['TracksController_deleteTrackCover']
    options?: never
    head?: never
    patch?: never
    trace?: never
  }
  '/playlists/tracks/upload': {
    parameters: {
      query?: never
      header?: never
      path?: never
      cookie?: never
    }
    get?: never
    put?: never
    /** Create a track with MP3 file upload */
    post: operations['TracksController_uploadTrackMp3']
    delete?: never
    options?: never
    head?: never
    patch?: never
    trace?: never
  }
  '/artists': {
    parameters: {
      query?: never
      header?: never
      path?: never
      cookie?: never
    }
    get?: never
    put?: never
    /** Create a new artist */
    post: operations['ArtistsController_createArtist']
    delete?: never
    options?: never
    head?: never
    patch?: never
    trace?: never
  }
  '/artists/search': {
    parameters: {
      query?: never
      header?: never
      path?: never
      cookie?: never
    }
    /** Search artists by substring */
    get: operations['ArtistsController_searchArtist']
    put?: never
    post?: never
    delete?: never
    options?: never
    head?: never
    patch?: never
    trace?: never
  }
  '/artists/{id}': {
    parameters: {
      query?: never
      header?: never
      path?: never
      cookie?: never
    }
    get?: never
    put?: never
    post?: never
    /** Delete an artist by ID */
    delete: operations['ArtistsController_deleteArtist']
    options?: never
    head?: never
    patch?: never
    trace?: never
  }
  '/auth/oauth-redirect': {
    parameters: {
      query?: never
      header?: never
      path?: never
      cookie?: never
    }
    /**
     * OAuth redirect
     * @description The callback URL to redirect after granting access, <a target="_blank" href="https://oauth.apihub.it-incubator.io/realms/apihub/protocol/openid-connect/auth?client_id=musicfun&response_type=code&redirect_uri=http://localhost:3000/oauth2/callback&scope=openid">https://oauth.apihub.it-incubator.io/realms/apihub/protocol/openid-connect/auth?client_id=musicfun&response_type=code&redirect_uri=http://localhost:3000/oauth2/callback&scope=openid</a>
     */
    get: operations['AuthController_OauthRedirect']
    put?: never
    post?: never
    delete?: never
    options?: never
    head?: never
    patch?: never
    trace?: never
  }
  '/auth/login': {
    parameters: {
      query?: never
      header?: never
      path?: never
      cookie?: never
    }
    get?: never
    put?: never
    /** Log in using the code received after OAuth authorization redirect */
    post: operations['AuthController_login']
    delete?: never
    options?: never
    head?: never
    patch?: never
    trace?: never
  }
  '/auth/refresh': {
    parameters: {
      query?: never
      header?: never
      path?: never
      cookie?: never
    }
    get?: never
    put?: never
    /** Refresh refresh/access token pair */
    post: operations['AuthController_refresh']
    delete?: never
    options?: never
    head?: never
    patch?: never
    trace?: never
  }
  '/auth/logout': {
    parameters: {
      query?: never
      header?: never
      path?: never
      cookie?: never
    }
    get?: never
    put?: never
    /** Deactivate refresh token */
    post: operations['AuthController_logout']
    delete?: never
    options?: never
    head?: never
    patch?: never
    trace?: never
  }
  '/auth/me': {
    parameters: {
      query?: never
      header?: never
      path?: never
      cookie?: never
    }
    /** Get current user by access token */
    get: operations['AuthController_getMe']
    put?: never
    post?: never
    delete?: never
    options?: never
    head?: never
    patch?: never
    trace?: never
  }
  '/tags': {
    parameters: {
      query?: never
      header?: never
      path?: never
      cookie?: never
    }
    get?: never
    put?: never
    /** Create a new tag */
    post: operations['TagsController_createTag']
    delete?: never
    options?: never
    head?: never
    patch?: never
    trace?: never
  }
  '/tags/search': {
    parameters: {
      query?: never
      header?: never
      path?: never
      cookie?: never
    }
    /** Search tags by substring */
    get: operations['TagsController_searchTags']
    put?: never
    post?: never
    delete?: never
    options?: never
    head?: never
    patch?: never
    trace?: never
  }
  '/tags/{id}': {
    parameters: {
      query?: never
      header?: never
      path?: never
      cookie?: never
    }
    get?: never
    put?: never
    post?: never
    /** Delete a tag by ID */
    delete: operations['TagsController_deleteTag']
    options?: never
    head?: never
    patch?: never
    trace?: never
  }
}
export type webhooks = Record<string, never>
export interface components {
  schemas: {
    UserRef: {
      /** @description Unique identifier of the user */
      id: string
      /** @description Name of the user */
      name: string
    }
    /**
     * @description Type of the image size (e.g., original, thumbnail variants)
     * @enum {string}
     */
    ImageSizeType: ImageSizeType
    ImageVariant: {
      /** @description Type of the image size (e.g., original, thumbnail variants) */
      type: components['schemas']['ImageSizeType']
      /** @description Image width in pixels */
      width: number
      /** @description Image height in pixels */
      height: number
      /** @description Image file size in bytes */
      fileSize: number
      /** @description Full public URL of the image */
      url: string
    }
    PlaylistImagesOutputDTO: {
      /** @description Original images and thumbnail previews */
      main?: components['schemas']['ImageVariant'][]
    }
    TagRef: {
      /** @description Unique identifier of the tag */
      id: string
      /** @description Original name of the tag */
      name: string
    }
    /**
     * @description User reaction: 0 – guest or no reaction; 1 – like; -1 – dislike
     * @enum {number}
     */
    ReactionValue: ReactionValue
    PlaylistListItemAttributes: {
      /** @description Title of the playlist */
      title: string
      /** @description Description of the playlist */
      description: string | null
      /**
       * Format: date-time
       * @description Date and time when the playlist was added (ISO 8601)
       */
      addedAt: string
      /**
       * Format: date-time
       * @description Date and time when the playlist was last updated (ISO 8601)
       */
      updatedAt: string
      /** @description Order index of the playlist */
      order: number
      /** @description User who created the playlist */
      user: components['schemas']['UserRef']
      /** @description Images associated with the playlist */
      images: components['schemas']['PlaylistImagesOutputDTO']
      /** @description Tags linked to the playlist */
      tags: components['schemas']['TagRef'][]
      /** @description Total number of likes for this playlist */
      likesCount: number
      /** @description Total number of dislikes for this playlist */
      dislikesCount: number
      /** @description User reaction: 0 – guest or no reaction; 1 – like; -1 – dislike */
      currentUserReaction: components['schemas']['ReactionValue']
    }
    PlaylistListItemResource: {
      /** @description Unique identifier of the playlist */
      id: string
      /**
       * @description Resource type (should be "playlists")
       * @example playlists
       */
      type: string
      attributes: components['schemas']['PlaylistListItemAttributes']
    }
    GetMyPlaylistsOutput: {
      /** @description Array of playlist resource objects owned by the current user */
      data: components['schemas']['PlaylistListItemResource'][]
    }
    CreatePlaylistRequestPayload: {
      /** @description Playlist title (1 to 100 characters) */
      title: string
      /** @description Playlist description (up to 1000 characters) */
      description: string | null
    }
    PlaylistAttributes: {
      /** @description Title of the playlist */
      title: string
      /** @description Description of the playlist */
      description: string | null
      /**
       * Format: date-time
       * @description Date and time when the playlist was added (ISO 8601)
       */
      addedAt: string
      /**
       * Format: date-time
       * @description Date and time when the playlist was last updated (ISO 8601)
       */
      updatedAt: string
      /** @description Order index of the playlist */
      order: number
      /** @description User who created the playlist */
      user: components['schemas']['UserRef']
      /** @description Images associated with the playlist */
      images: components['schemas']['PlaylistImagesOutputDTO']
      /** @description Tags linked to the playlist */
      tags: components['schemas']['TagRef'][]
      /** @description Total number of likes for this playlist */
      likesCount: number
      /** @description Total number of dislikes for this playlist */
      dislikesCount: number
      /** @description User reaction: 0 – guest or no reaction; 1 – like; -1 – dislike */
      currentUserReaction: components['schemas']['ReactionValue']
    }
    PlaylistResource: {
      /** @description Unique identifier of the playlist */
      id: string
      /**
       * @description Resource type (should be "playlists")
       * @example playlists
       */
      type: string
      attributes: components['schemas']['PlaylistAttributes']
    }
    GetPlaylistOutput: {
      data: components['schemas']['PlaylistResource']
    }
    UpdatePlaylistRequestPayload: {
      /** @description Playlist title (1 – 100 characters) */
      title: string
      /**
       * @description Playlist description (up to 1000 characters)
       * @example Cool playlist
       */
      description: string | null
      /** @description Tag IDs to associate with the playlist (0 – 5 items; [] = clear tags) */
      tagIds: string[]
    }
    ReorderPlaylistsRequestPayload: {
      /**
       * Format: uuid
       * @description ID of the playlist after which the current playlist should be inserted. Send null to place the playlist at the beginning of the list.
       */
      putAfterItemId: string | null
    }
    TrackImages: {
      /** @description List of original images and thumbnail versions (e.g., original, 320x180, etc.) */
      main?: components['schemas']['ImageVariant'][]
    }
    GetTracksRequestPayload: {
      /**
       * @description Page number for pagination (starting from 1)
       * @default 1
       */
      pageNumber: number
      /**
       * @description Page size for pagination (between 1 and 20)
       * @default 20
       */
      pageSize: number
      /** @description Search term for filtering playlists by name */
      search?: string
      /**
       * @description Field by which to sort tracks
       * @default publishedAt
       * @enum {string}
       */
      sortBy: PathsPlaylistsTracksGetParametersQuerySortBy
      /**
       * @description Sort direction (ascending or descending)
       * @default desc
       * @enum {string}
       */
      sortDirection: PathsPlaylistsGetParametersQuerySortDirection
      /** @description Filter by tag IDs (multiple values allowed) */
      tagsIds?: string[]
      /** @description Filter by artist IDs (multiple values allowed) */
      artistsIds?: string[]
      /** @description Filter by user ID (track creator's ID) */
      userId?: string
      /** @description If true, include unpublished tracks (drafts) of current user if userId === currentUserId */
      includeDrafts?: boolean
      /**
       * @description Pagination type: "offset" for page-number pagination; "cursor" for keyset/seek-based pagination.
       * @default offset
       * @enum {string}
       */
      paginationType: PathsPlaylistsTracksGetParametersQueryPaginationType
      /** @description Base64-encoded cursor for keyset pagination. Used only if paginationType is "cursor". */
      cursor?: string | null
    }
    JsonApiErrorSource: {
      /**
       * @description e.g. "/data/attributes/field"
       * @example /data/attributes/field
       */
      pointer?: string
      /**
       * @description e.g. "?queryParam"
       * @example ?queryParam
       */
      parameter?: string
    }
    JsonApiError: {
      /**
       * @description HTTP status code as a string
       * @example 404
       */
      status: string
      /**
       * @description Application-specific error code
       * @example E123
       */
      code?: Record<string, never>
      /**
       * @description Short, human-readable summary
       * @example Not Found
       */
      title?: string
      /**
       * @description Detailed explanation
       * @example User with ID 123 not found
       */
      detail?: string
      /** @description Pointer to the associated entity in the request */
      source?: components['schemas']['JsonApiErrorSource']
      /** @description Any extra data */
      meta?: Record<string, never>
    }
    JsonApiErrorDocument: {
      /** @description Array of one or more errors */
      errors: components['schemas']['JsonApiError'][]
      /** @description e.g. timestamp, path, traceId, etc. */
      meta?: Record<string, never>
    }
    TrackAttachment: {
      /** @description Unique identifier of the entity */
      id: string
      /**
       * Format: date-time
       * @description Date and time when the entity was added
       */
      addedAt: string
      /**
       * Format: date-time
       * @description Date and time when the entity was last updated
       */
      updatedAt: string
      /** @description Version number of the entity (for concurrency control) */
      version: number
      /**
       * @description Public URL to access the uploaded file
       * @example https://cdn.example.com/uploads/track123/cover.jpg
       */
      url: string
      /**
       * @description MIME type of the file
       * @example image/jpeg
       */
      contentType: string
      /**
       * @description Original filename uploaded by the user
       * @example cover.jpg
       */
      originalName: string
      /**
       * @description Size of the file in bytes
       * @example 34872
       */
      fileSize: number
    }
    TrackListItemAttributes: {
      title: string
      /**
       * Format: date-time
       * @description Date and time when the track was added (ISO 8601)
       */
      addedAt: string
      likesCount: number
      attachments: components['schemas']['TrackAttachment'][]
      images: components['schemas']['TrackImages']
      user: components['schemas']['UserRef']
      /**
       * @description 0 – не залогинен или не реагировал; 1 – лайк; −1 – дизлайк
       * @enum {number}
       */
      currentUserReaction: ReactionValue
      isPublished: boolean
      /**
       * Format: date-time
       * @description Date and time when the track was published (ISO 8601)
       */
      publishedAt?: string | null
    }
    ArtistRelationship: {
      id: string
      type: string
    }
    ArtistsRelationship: {
      data: components['schemas']['ArtistRelationship'][]
    }
    TrackRelationships: {
      artists: components['schemas']['ArtistsRelationship']
    }
    TrackListItemResource: {
      id: string
      /** @example tracks */
      type: string
      attributes: components['schemas']['TrackListItemAttributes']
      relationships: components['schemas']['TrackRelationships']
    }
    JsonApiMetaWithPagingAndCursor: {
      page: number
      pageSize: number
      /** @description Total count may be absent when using keyset pagination */
      totalCount: number | null
      /** @description Total number of pages */
      pagesCount: number | null
      /** @description Cursor for the next page */
      nextCursor: string | null
    }
    OmitTypeClass: {
      /** @description Name of the artist */
      name: string
    }
    IncludedArtistOutput: {
      id: string
      type: string
      attributes: components['schemas']['OmitTypeClass']
    }
    GetTrackListOutput: {
      data: components['schemas']['TrackListItemResource'][]
      meta: components['schemas']['JsonApiMetaWithPagingAndCursor']
      included: components['schemas']['IncludedArtistOutput'][]
    }
    TrackListItemAttributesForPlaylist: {
      /** @description Title of the track */
      title: string
      /** @description Order index of the track in the playlist */
      order: number
      /**
       * Format: date-time
       * @description Date and time when the track was added (ISO 8601)
       */
      addedAt: string
      /**
       * Format: date-time
       * @description Date and time when the track was last updated (ISO 8601)
       */
      updatedAt: string
      /** @description Attachments related to the track */
      attachments: components['schemas']['TrackAttachment'][]
      /** @description Images associated with the track */
      images: components['schemas']['TrackImages']
      /**
       * @description User reaction: 0 – guest or no reaction; 1 – liked; -1 – disliked
       * @enum {number|null}
       */
      currentUserReaction: ReactionValue
      /**
       * Format: date-time
       * @description Date and time when the track was published (ISO 8601)
       */
      publishedAt?: string | null
    }
    TrackListItemResourceForPlaylist: {
      id: string
      /** @example tracks */
      type: string
      attributes: components['schemas']['TrackListItemAttributesForPlaylist']
      relationships: components['schemas']['TrackRelationships']
    }
    JsonApiMeta: {
      totalCount: number
    }
    GetTracksForPlaylistOutput: {
      data: components['schemas']['TrackListItemResourceForPlaylist'][]
      meta: components['schemas']['JsonApiMeta']
      included: components['schemas']['IncludedArtistOutput'][]
    }
    ArtistRef: {
      /** @description Unique identifier of the artist */
      id: string
      /** @description Name of the artist */
      name: string
    }
    TrackDetailsAttributes: {
      /** @description Track title */
      title: string
      /** @description Track lyrics text */
      lyrics?: string | null
      /**
       * Format: date-time
       * @description Release date in ISO 8601 format
       */
      releaseDate?: string | null
      /**
       * Format: date-time
       * @description Date and time when the track was added (ISO 8601)
       */
      addedAt: string
      /**
       * Format: date-time
       * @description Date and time when the track was last updated (ISO 8601)
       */
      updatedAt: string
      /** @description Duration of the track in seconds */
      duration: number
      /** @description Total number of likes for this track */
      likesCount: number
      /**
       * @deprecated
       * @description Total number of dislikes for this track
       */
      dislikesCount: number
      /** @description List of attachments related to the track */
      attachments: components['schemas']['TrackAttachment'][]
      images: components['schemas']['TrackImages']
      /** @description Tags associated with the track */
      tags: components['schemas']['TagRef'][]
      /** @description Artists associated with the track */
      artists: components['schemas']['ArtistRef'][]
      user: components['schemas']['UserRef']
      /** @description Publication status of the track */
      isPublished: boolean
      /**
       * Format: date-time
       * @description Publication date in ISO 8601 format
       */
      publishedAt?: string | null
      /**
       * @description User reaction: 0 – guest or no reaction; 1 – user liked; -1 – user disliked
       * @enum {number}
       */
      currentUserReaction: ReactionValue
    }
    TrackDetailsResource: {
      /** @description Unique identifier of the track */
      id: string
      /**
       * @description Resource type (should be "tracks")
       * @example tracks
       */
      type: string
      attributes: components['schemas']['TrackDetailsAttributes']
    }
    GetTrackDetailsOutput: {
      data: components['schemas']['TrackDetailsResource']
    }
    ReactionOutput: {
      objectId: string
      /** @enum {number} */
      value: ReactionValue
      likes: number
      dislikes: number
    }
    GetPlaylistsRequestPayload: {
      /**
       * @description Page number for pagination (starting from 1)
       * @default 1
       */
      pageNumber: number
      /**
       * @description Page size for pagination (between 1 and 20)
       * @default 20
       */
      pageSize: number
      /** @description Search term for filtering playlists by name */
      search?: string
      /**
       * @description Field by which to sort playlists
       * @default addedAt
       * @enum {string}
       */
      sortBy: PathsPlaylistsGetParametersQuerySortBy
      /**
       * @description Sort direction (ascending or descending)
       * @default desc
       * @enum {string}
       */
      sortDirection: PathsPlaylistsGetParametersQuerySortDirection
      /** @description Filter by tag IDs. Multiple values allowed, e.g.: tagsIds=tag1&tagsIds=tag2 */
      tagsIds?: string[]
      /** @description Filter by user ID (playlist creator’s ID) */
      userId?: string
      /** @description Filter by track ID – only playlists containing this track will be returned */
      trackId?: string
    }
    JsonApiMetaWithPaging: {
      totalCount: number
      page: number
      pageSize: number
      pagesCount: number
    }
    GetPlaylistsOutput: {
      /** @description Array of playlist resource objects */
      data: components['schemas']['PlaylistListItemResource'][]
      meta: components['schemas']['JsonApiMetaWithPaging']
    }
    ReorderTracksRequestPayload: {
      /**
       * Format: uuid
       * @description ID of the track after which the current track should be inserted. Send null to place the track at the beginning of the list.
       * @example a1b2c3d4-e5f6-7890-abcd-1234567890ef
       */
      putAfterItemId: string | null
    }
    UpdateTrackRequestPayload: {
      /** @description Track title (1 to 100 characters) */
      title: string
      /** @description Track lyrics (up to 5000 characters) */
      lyrics: string | null
      /**
       * Format: date-time
       * @description Release date in ISO 8601 format
       */
      releaseDate: string | null
      /** @description Array of tag IDs to associate with the track (up to 5) */
      tagIds: string[]
      /** @description Array of artist IDs to associate with the track (up to 5) */
      artistsIds: string[]
    }
    AddTrackToPlaylistRequestPayload: {
      /** @description ID of the track to add to the playlist */
      trackId: string
    }
    CreateArtistRequestPayload: {
      /** @description Artist name (must be between 2 and 30 characters) */
      name: string
    }
    LoginRequestPayload: {
      /** @description Authorization code received from OAuth server after redirect */
      code: string
      /**
       * @description Specify the same redirect URI used in the initial OAuth server request
       * @example http://localhost:3000/oauth2/callback
       */
      redirectUri: string
      /**
       * @description Access token lifetime (default "3m"); must be a string like "60s", "3m", "2h", or "1d"
       * @example 3m
       */
      accessTokenTTL?: string
      /** @description Refresh token lifetime: if true, 30 days; if false, 30 minutes. accessTokenTTL must not exceed the refresh token lifetime */
      rememberMe: boolean
    }
    RefreshOutput: {
      refreshToken: string
      accessToken: string
    }
    BadRequestException: Record<string, never>
    UnauthorizedException: Record<string, never>
    RefreshRequestPayload: {
      refreshToken: string
    }
    LogoutRequestPayload: {
      refreshToken: string
    }
    GetMeOutput: {
      userId: string
      login: string
    }
    CreateTagRequestPayload: {
      /** @description Tag name (2 to 30 characters) */
      name: string
    }
    /**
     * Format: binary
     * @description Файл в multipart/form-data
     */
    BinaryFile: string
  }
  responses: never
  parameters: never
  requestBodies: never
  headers: never
  pathItems: never
}
export type SchemaUserRef = components['schemas']['UserRef']
export type SchemaImageVariant = components['schemas']['ImageVariant']
export type SchemaPlaylistImagesOutputDto = components['schemas']['PlaylistImagesOutputDTO']
export type SchemaTagRef = components['schemas']['TagRef']
export type SchemaPlaylistListItemAttributes = components['schemas']['PlaylistListItemAttributes']
export type SchemaPlaylistListItemResource = components['schemas']['PlaylistListItemResource']
export type SchemaGetMyPlaylistsOutput = components['schemas']['GetMyPlaylistsOutput']
export type SchemaCreatePlaylistRequestPayload =
  components['schemas']['CreatePlaylistRequestPayload']
export type SchemaPlaylistAttributes = components['schemas']['PlaylistAttributes']
export type SchemaPlaylistResource = components['schemas']['PlaylistResource']
export type SchemaGetPlaylistOutput = components['schemas']['GetPlaylistOutput']
export type SchemaUpdatePlaylistRequestPayload =
  components['schemas']['UpdatePlaylistRequestPayload']
export type SchemaReorderPlaylistsRequestPayload =
  components['schemas']['ReorderPlaylistsRequestPayload']
export type SchemaTrackImages = components['schemas']['TrackImages']
export type SchemaGetTracksRequestPayload = components['schemas']['GetTracksRequestPayload']
export type SchemaJsonApiErrorSource = components['schemas']['JsonApiErrorSource']
export type SchemaJsonApiError = components['schemas']['JsonApiError']
export type SchemaJsonApiErrorDocument = components['schemas']['JsonApiErrorDocument']
export type SchemaTrackAttachment = components['schemas']['TrackAttachment']
export type SchemaTrackListItemAttributes = components['schemas']['TrackListItemAttributes']
export type SchemaArtistRelationship = components['schemas']['ArtistRelationship']
export type SchemaArtistsRelationship = components['schemas']['ArtistsRelationship']
export type SchemaTrackRelationships = components['schemas']['TrackRelationships']
export type SchemaTrackListItemResource = components['schemas']['TrackListItemResource']
export type SchemaJsonApiMetaWithPagingAndCursor =
  components['schemas']['JsonApiMetaWithPagingAndCursor']
export type SchemaOmitTypeClass = components['schemas']['OmitTypeClass']
export type SchemaIncludedArtistOutput = components['schemas']['IncludedArtistOutput']
export type SchemaGetTrackListOutput = components['schemas']['GetTrackListOutput']
export type SchemaTrackListItemAttributesForPlaylist =
  components['schemas']['TrackListItemAttributesForPlaylist']
export type SchemaTrackListItemResourceForPlaylist =
  components['schemas']['TrackListItemResourceForPlaylist']
export type SchemaJsonApiMeta = components['schemas']['JsonApiMeta']
export type SchemaGetTracksForPlaylistOutput = components['schemas']['GetTracksForPlaylistOutput']
export type SchemaArtistRef = components['schemas']['ArtistRef']
export type SchemaTrackDetailsAttributes = components['schemas']['TrackDetailsAttributes']
export type SchemaTrackDetailsResource = components['schemas']['TrackDetailsResource']
export type SchemaGetTrackDetailsOutput = components['schemas']['GetTrackDetailsOutput']
export type SchemaReactionOutput = components['schemas']['ReactionOutput']
export type SchemaGetPlaylistsRequestPayload = components['schemas']['GetPlaylistsRequestPayload']
export type SchemaJsonApiMetaWithPaging = components['schemas']['JsonApiMetaWithPaging']
export type SchemaGetPlaylistsOutput = components['schemas']['GetPlaylistsOutput']
export type SchemaReorderTracksRequestPayload = components['schemas']['ReorderTracksRequestPayload']
export type SchemaUpdateTrackRequestPayload = components['schemas']['UpdateTrackRequestPayload']
export type SchemaAddTrackToPlaylistRequestPayload =
  components['schemas']['AddTrackToPlaylistRequestPayload']
export type SchemaCreateArtistRequestPayload = components['schemas']['CreateArtistRequestPayload']
export type SchemaLoginRequestPayload = components['schemas']['LoginRequestPayload']
export type SchemaRefreshOutput = components['schemas']['RefreshOutput']
export type SchemaBadRequestException = components['schemas']['BadRequestException']
export type SchemaUnauthorizedException = components['schemas']['UnauthorizedException']
export type SchemaRefreshRequestPayload = components['schemas']['RefreshRequestPayload']
export type SchemaLogoutRequestPayload = components['schemas']['LogoutRequestPayload']
export type SchemaGetMeOutput = components['schemas']['GetMeOutput']
export type SchemaCreateTagRequestPayload = components['schemas']['CreateTagRequestPayload']
export type SchemaBinaryFile = components['schemas']['BinaryFile']
export type $defs = Record<string, never>
export interface operations {
  PlaylistsController_getMyPlaylists: {
    parameters: {
      query?: never
      header?: never
      path?: never
      cookie?: never
    }
    requestBody?: never
    responses: {
      /** @description OK: List of playlists retrieved successfully */
      200: {
        headers: {
          [name: string]: unknown
        }
        content: {
          'application/json': components['schemas']['GetMyPlaylistsOutput']
        }
      }
      /** @description Unauthorized: User not authenticated */
      401: {
        headers: {
          [name: string]: unknown
        }
        content?: never
      }
    }
  }
  PlaylistsPublicController_getPlaylists: {
    parameters: {
      query?: {
        /** @description Page number for pagination (starting from 1) */
        pageNumber?: number
        /** @description Page size for pagination (between 1 and 20) */
        pageSize?: number
        /** @description Search term for filtering playlists by name */
        search?: string
        /** @description Field by which to sort playlists */
        sortBy?: PathsPlaylistsGetParametersQuerySortBy
        /** @description Sort direction (ascending or descending) */
        sortDirection?: PathsPlaylistsGetParametersQuerySortDirection
        /** @description Filter by tag IDs. Multiple values allowed, e.g.: tagsIds=tag1&tagsIds=tag2 */
        tagsIds?: string[]
        /** @description Filter by user ID (playlist creator’s ID) */
        userId?: string
        /** @description Filter by track ID – only playlists containing this track will be returned */
        trackId?: string
      }
      header?: never
      path?: never
      cookie?: never
    }
    requestBody?: never
    responses: {
      /** @description OK: JSON:API list of playlists with pagination */
      200: {
        headers: {
          [name: string]: unknown
        }
        content: {
          'application/json': components['schemas']['GetPlaylistsOutput']
        }
      }
    }
  }
  PlaylistsController_createPlaylist: {
    parameters: {
      query?: never
      header?: never
      path?: never
      cookie?: never
    }
    requestBody: {
      content: {
        'application/json': components['schemas']['CreatePlaylistRequestPayload']
      }
    }
    responses: {
      /** @description Created: Playlist created successfully */
      201: {
        headers: {
          [name: string]: unknown
        }
        content: {
          'application/json': components['schemas']['GetPlaylistOutput']
        }
      }
      /** @description Forbidden: Playlist creation limit exceeded */
      403: {
        headers: {
          [name: string]: unknown
        }
        content?: never
      }
    }
  }
  PlaylistsPublicController_getPlaylistById: {
    parameters: {
      query?: never
      header?: never
      path: {
        /** @description ID of the playlist */
        playlistId: string
      }
      cookie?: never
    }
    requestBody?: never
    responses: {
      /** @description OK: Playlist retrieved successfully */
      200: {
        headers: {
          [name: string]: unknown
        }
        content: {
          'application/json': components['schemas']['GetPlaylistOutput']
        }
      }
      /** @description Not Found: Playlist with the given ID not found */
      404: {
        headers: {
          [name: string]: unknown
        }
        content?: never
      }
    }
  }
  PlaylistsController_updatePlaylist: {
    parameters: {
      query?: never
      header?: never
      path: {
        playlistId: string
      }
      cookie?: never
    }
    requestBody: {
      content: {
        'application/json': components['schemas']['UpdatePlaylistRequestPayload']
      }
    }
    responses: {
      /** @description No Content: Playlist updated successfully */
      204: {
        headers: {
          [name: string]: unknown
        }
        content?: never
      }
      /** @description Bad Request: Validation error (e.g., tag limit exceeded) */
      400: {
        headers: {
          [name: string]: unknown
        }
        content?: never
      }
      /** @description Forbidden: You do not have permission to update this playlist */
      403: {
        headers: {
          [name: string]: unknown
        }
        content?: never
      }
    }
  }
  PlaylistsController_deletePlaylist: {
    parameters: {
      query?: never
      header?: never
      path: {
        playlistId: string
      }
      cookie?: never
    }
    requestBody?: never
    responses: {
      /** @description No Content: Playlist deleted successfully */
      204: {
        headers: {
          [name: string]: unknown
        }
        content?: never
      }
      /** @description Forbidden: Insufficient permissions to delete this playlist */
      403: {
        headers: {
          [name: string]: unknown
        }
        content?: never
      }
      /** @description Not Found: Playlist not found */
      404: {
        headers: {
          [name: string]: unknown
        }
        content?: never
      }
    }
  }
  PlaylistsController_reorderPlaylist: {
    parameters: {
      query?: never
      header?: never
      path: {
        playlistId: string
      }
      cookie?: never
    }
    requestBody: {
      content: {
        'application/json': components['schemas']['ReorderPlaylistsRequestPayload']
      }
    }
    responses: {
      /** @description No Content: Playlist order updated successfully */
      204: {
        headers: {
          [name: string]: unknown
        }
        content?: never
      }
      /** @description Not Found: Playlist or putAfterItemId not found */
      404: {
        headers: {
          [name: string]: unknown
        }
        content?: never
      }
    }
  }
  PlaylistsController_uploadMainImage: {
    parameters: {
      query?: never
      header?: never
      path: {
        playlistId: string
      }
      cookie?: never
    }
    requestBody: {
      content: {
        'multipart/form-data': {
          /** @description Maximum size 1 MB; minimum height 500px; image must be square */
          file: components['schemas']['BinaryFile']
        }
      }
    }
    responses: {
      /** @description OK: Cover uploaded successfully */
      200: {
        headers: {
          [name: string]: unknown
        }
        content: {
          'application/json': components['schemas']['TrackImages']
        }
      }
      /** @description Bad Request: Invalid image format or dimensions */
      400: {
        headers: {
          [name: string]: unknown
        }
        content?: never
      }
      /** @description Forbidden: No permission to upload cover for this playlist */
      403: {
        headers: {
          [name: string]: unknown
        }
        content?: never
      }
    }
  }
  PlaylistsController_deleteTrackCover: {
    parameters: {
      query?: never
      header?: never
      path: {
        playlistId: string
      }
      cookie?: never
    }
    requestBody?: never
    responses: {
      /** @description No Content: Cover deleted successfully */
      204: {
        headers: {
          [name: string]: unknown
        }
        content?: never
      }
      /** @description Forbidden: Removing another user’s playlist cover is not allowed */
      403: {
        headers: {
          [name: string]: unknown
        }
        content?: never
      }
      /** @description Not Found: Playlist not found */
      404: {
        headers: {
          [name: string]: unknown
        }
        content?: never
      }
    }
  }
  TracksPublicController_getAllTracks: {
    parameters: {
      query?: {
        /** @description Page number for pagination (starting from 1) */
        pageNumber?: number
        /** @description Page size for pagination (between 1 and 20) */
        pageSize?: number
        /** @description Search term for filtering playlists by name */
        search?: string
        /** @description Field by which to sort tracks */
        sortBy?: PathsPlaylistsTracksGetParametersQuerySortBy
        /** @description Sort direction (ascending or descending) */
        sortDirection?: PathsPlaylistsGetParametersQuerySortDirection
        /** @description Filter by tag IDs (multiple values allowed) */
        tagsIds?: string[]
        /** @description Filter by artist IDs (multiple values allowed) */
        artistsIds?: string[]
        /** @description Filter by user ID (track creator's ID) */
        userId?: string
        /** @description If true, include unpublished tracks (drafts) of current user if userId === currentUserId */
        includeDrafts?: boolean
        /** @description Pagination type: "offset" for page-number pagination; "cursor" for keyset/seek-based pagination. */
        paginationType?: PathsPlaylistsTracksGetParametersQueryPaginationType
        /** @description Base64-encoded cursor for keyset pagination. Used only if paginationType is "cursor". */
        cursor?: string | null
      }
      header?: never
      path?: never
      cookie?: never
    }
    requestBody?: never
    responses: {
      /** @description OK: Paginated list of tracks */
      200: {
        headers: {
          [name: string]: unknown
        }
        content: {
          'application/json': components['schemas']['GetTrackListOutput']
        }
      }
      /** @description Bad Request: invalid query parameters */
      400: {
        headers: {
          [name: string]: unknown
        }
        content: {
          'application/json': components['schemas']['JsonApiErrorDocument']
        }
      }
    }
  }
  TracksPublicController_getPlaylistTracks: {
    parameters: {
      query?: never
      header?: never
      path: {
        /** @description ID of the playlist to retrieve tracks for */
        playlistId: string
      }
      cookie?: never
    }
    requestBody?: never
    responses: {
      /** @description OK: List of tracks in the playlist */
      200: {
        headers: {
          [name: string]: unknown
        }
        content: {
          'application/json': components['schemas']['GetTracksForPlaylistOutput']
        }
      }
      /** @description Not Found: Playlist with the specified ID not found */
      404: {
        headers: {
          [name: string]: unknown
        }
        content?: never
      }
    }
  }
  TracksPublicController_getTrackDetails: {
    parameters: {
      query?: never
      header?: never
      path: {
        /** @description ID of the track to retrieve details for */
        trackId: string
      }
      cookie?: never
    }
    requestBody?: never
    responses: {
      /** @description OK: Track details with attachments */
      200: {
        headers: {
          [name: string]: unknown
        }
        content: {
          'application/json': components['schemas']['GetTrackDetailsOutput']
        }
      }
      /** @description Not Found: Track with the specified ID not found */
      404: {
        headers: {
          [name: string]: unknown
        }
        content?: never
      }
    }
  }
  TracksController_updateTrack: {
    parameters: {
      query?: never
      header?: never
      path: {
        trackId: string
      }
      cookie?: never
    }
    requestBody: {
      content: {
        'application/json': components['schemas']['UpdateTrackRequestPayload']
      }
    }
    responses: {
      /** @description OK: Track updated successfully */
      200: {
        headers: {
          [name: string]: unknown
        }
        content: {
          'application/json': components['schemas']['GetTrackDetailsOutput']
        }
      }
      /** @description Bad Request: Tag or artist limit exceeded */
      400: {
        headers: {
          [name: string]: unknown
        }
        content?: never
      }
      /** @description Forbidden: Editing another user’s track is not allowed */
      403: {
        headers: {
          [name: string]: unknown
        }
        content?: never
      }
      /** @description Not Found: Track or playlist not found */
      404: {
        headers: {
          [name: string]: unknown
        }
        content?: never
      }
    }
  }
  TracksController_deleteTrackCompletely: {
    parameters: {
      query?: never
      header?: never
      path: {
        trackId: string
      }
      cookie?: never
    }
    requestBody?: never
    responses: {
      /** @description No Content: Track permanently deleted */
      204: {
        headers: {
          [name: string]: unknown
        }
        content?: never
      }
      /** @description Forbidden: Deleting another user’s track is not allowed */
      403: {
        headers: {
          [name: string]: unknown
        }
        content?: never
      }
      /** @description Not Found: Track not found */
      404: {
        headers: {
          [name: string]: unknown
        }
        content?: never
      }
    }
  }
  TracksPublicController_likeTrack: {
    parameters: {
      query?: never
      header?: never
      path: {
        trackId: string
      }
      cookie?: never
    }
    requestBody?: never
    responses: {
      /** @description Created: User reaction recorded and counters updated */
      201: {
        headers: {
          [name: string]: unknown
        }
        content: {
          'application/json': components['schemas']['ReactionOutput']
        }
      }
      /** @description Bad Request: Invalid track ID */
      400: {
        headers: {
          [name: string]: unknown
        }
        content?: never
      }
      /** @description Unauthorized: User not authenticated */
      401: {
        headers: {
          [name: string]: unknown
        }
        content?: never
      }
      /** @description Not Found: Track not found */
      404: {
        headers: {
          [name: string]: unknown
        }
        content?: never
      }
    }
  }
  TracksPublicController_dislikeTrack: {
    parameters: {
      query?: never
      header?: never
      path: {
        trackId: string
      }
      cookie?: never
    }
    requestBody?: never
    responses: {
      /** @description Created: User reaction recorded and counters updated */
      201: {
        headers: {
          [name: string]: unknown
        }
        content: {
          'application/json': components['schemas']['ReactionOutput']
        }
      }
      /** @description Bad Request: Invalid track ID */
      400: {
        headers: {
          [name: string]: unknown
        }
        content?: never
      }
      /** @description Unauthorized: User not authenticated */
      401: {
        headers: {
          [name: string]: unknown
        }
        content?: never
      }
      /** @description Not Found: Track not found */
      404: {
        headers: {
          [name: string]: unknown
        }
        content?: never
      }
    }
  }
  TracksPublicController_removeTrackReaction: {
    parameters: {
      query?: never
      header?: never
      path: {
        trackId: string
      }
      cookie?: never
    }
    requestBody?: never
    responses: {
      /** @description OK: Reaction removed successfully */
      200: {
        headers: {
          [name: string]: unknown
        }
        content: {
          'application/json': components['schemas']['ReactionOutput']
        }
      }
      /** @description Unauthorized: User not authenticated */
      401: {
        headers: {
          [name: string]: unknown
        }
        content?: never
      }
    }
  }
  PlaylistsPublicController_likePlaylist: {
    parameters: {
      query?: never
      header?: never
      path: {
        playlistId: string
      }
      cookie?: never
    }
    requestBody?: never
    responses: {
      /** @description Created: Like recorded successfully */
      201: {
        headers: {
          [name: string]: unknown
        }
        content: {
          'application/json': components['schemas']['ReactionOutput']
        }
      }
      /** @description Bad Request: Invalid playlist ID */
      400: {
        headers: {
          [name: string]: unknown
        }
        content?: never
      }
      /** @description Unauthorized */
      401: {
        headers: {
          [name: string]: unknown
        }
        content?: never
      }
      /** @description Not Found: Playlist not found */
      404: {
        headers: {
          [name: string]: unknown
        }
        content?: never
      }
    }
  }
  PlaylistsPublicController_dislikePlaylist: {
    parameters: {
      query?: never
      header?: never
      path: {
        playlistId: string
      }
      cookie?: never
    }
    requestBody?: never
    responses: {
      /** @description Created: Dislike recorded successfully */
      201: {
        headers: {
          [name: string]: unknown
        }
        content: {
          'application/json': components['schemas']['ReactionOutput']
        }
      }
      /** @description Bad Request: Invalid playlist ID */
      400: {
        headers: {
          [name: string]: unknown
        }
        content?: never
      }
      /** @description Unauthorized */
      401: {
        headers: {
          [name: string]: unknown
        }
        content?: never
      }
      /** @description Not Found: Playlist not found */
      404: {
        headers: {
          [name: string]: unknown
        }
        content?: never
      }
    }
  }
  PlaylistsPublicController_removePlaylistReaction: {
    parameters: {
      query?: never
      header?: never
      path: {
        playlistId: string
      }
      cookie?: never
    }
    requestBody?: never
    responses: {
      /** @description OK: Reaction removed successfully */
      200: {
        headers: {
          [name: string]: unknown
        }
        content: {
          'application/json': components['schemas']['ReactionOutput']
        }
      }
      /** @description Unauthorized */
      401: {
        headers: {
          [name: string]: unknown
        }
        content?: never
      }
      /** @description Not Found: Playlist not found */
      404: {
        headers: {
          [name: string]: unknown
        }
        content?: never
      }
    }
  }
  TracksController_reorderTrack: {
    parameters: {
      query?: never
      header?: never
      path: {
        playlistId: string
        trackId: string
      }
      cookie?: never
    }
    requestBody: {
      content: {
        'application/json': components['schemas']['ReorderTracksRequestPayload']
      }
    }
    responses: {
      /** @description OK: Track order updated successfully */
      200: {
        headers: {
          [name: string]: unknown
        }
        content?: never
      }
      /** @description Bad Request: Cannot place a track after itself */
      400: {
        headers: {
          [name: string]: unknown
        }
        content?: never
      }
      /** @description Forbidden: No access to the playlist */
      403: {
        headers: {
          [name: string]: unknown
        }
        content?: never
      }
      /** @description Not Found: Track or putAfterItemId not found */
      404: {
        headers: {
          [name: string]: unknown
        }
        content?: never
      }
    }
  }
  TracksController_addTrackToPlaylist: {
    parameters: {
      query?: never
      header?: never
      path: {
        playlistId: string
      }
      cookie?: never
    }
    requestBody: {
      content: {
        'application/json': components['schemas']['AddTrackToPlaylistRequestPayload']
      }
    }
    responses: {
      /** @description No Content: Track added to the playlist successfully */
      204: {
        headers: {
          [name: string]: unknown
        }
        content?: never
      }
      /** @description Forbidden: No access to the playlist or track limit exceeded (max 10 tracks) */
      403: {
        headers: {
          [name: string]: unknown
        }
        content?: never
      }
      /** @description Not Found: Playlist not found */
      404: {
        headers: {
          [name: string]: unknown
        }
        content?: never
      }
    }
  }
  TracksController_unbindTrackFromPlaylist: {
    parameters: {
      query?: never
      header?: never
      path: {
        playlistId: string
        trackId: string
      }
      cookie?: never
    }
    requestBody?: never
    responses: {
      /** @description No Content: Track removed from the playlist */
      204: {
        headers: {
          [name: string]: unknown
        }
        content?: never
      }
      /** @description Forbidden: No access to the playlist */
      403: {
        headers: {
          [name: string]: unknown
        }
        content?: never
      }
      /** @description Not Found: Playlist not found */
      404: {
        headers: {
          [name: string]: unknown
        }
        content?: never
      }
    }
  }
  TracksController_publishTrack: {
    parameters: {
      query?: never
      header?: never
      path: {
        trackId: string
      }
      cookie?: never
    }
    requestBody?: never
    responses: {
      /** @description No Content: Track published successfully */
      204: {
        headers: {
          [name: string]: unknown
        }
        content?: never
      }
      /** @description Forbidden: Publishing another user’s track is not allowed */
      403: {
        headers: {
          [name: string]: unknown
        }
        content?: never
      }
      /** @description Not Found: Track with the specified ID not found */
      404: {
        headers: {
          [name: string]: unknown
        }
        content?: never
      }
      /** @description Conflict: Track is already published */
      409: {
        headers: {
          [name: string]: unknown
        }
        content?: never
      }
    }
  }
  TracksController_uploadTrackCover: {
    parameters: {
      query?: never
      header?: never
      path: {
        /** @description ID of the track for which the cover is being uploaded */
        trackId: string
      }
      cookie?: never
    }
    /** @description Image file:<br/>
     *             • Field name — <code>cover</code><br/>
     *             • Allowed MIME types — <code>image/jpeg</code>, <code>image/png</code>, <code>image/gif</code><br/>
     *             • Maximum size — <code>100 KB</code> */
    requestBody: {
      content: {
        'multipart/form-data': {
          /** Format: binary */
          cover: string
        }
      }
    }
    responses: {
      /** @description OK: Cover uploaded successfully */
      200: {
        headers: {
          [name: string]: unknown
        }
        content: {
          'application/json': components['schemas']['TrackImages']
        }
      }
      /** @description Bad Request: Invalid file or size exceeded */
      400: {
        headers: {
          [name: string]: unknown
        }
        content?: never
      }
      /** @description Forbidden: Cannot upload a cover for another user’s track */
      403: {
        headers: {
          [name: string]: unknown
        }
        content?: never
      }
      /** @description Not Found: Track not found */
      404: {
        headers: {
          [name: string]: unknown
        }
        content?: never
      }
    }
  }
  TracksController_deleteTrackCover: {
    parameters: {
      query?: never
      header?: never
      path: {
        trackId: string
      }
      cookie?: never
    }
    requestBody?: never
    responses: {
      /** @description No Content: Cover deleted successfully */
      204: {
        headers: {
          [name: string]: unknown
        }
        content?: never
      }
      /** @description Forbidden: Removing another user's track cover is not allowed */
      403: {
        headers: {
          [name: string]: unknown
        }
        content?: never
      }
      /** @description Not Found: Track not found */
      404: {
        headers: {
          [name: string]: unknown
        }
        content?: never
      }
    }
  }
  TracksController_uploadTrackMp3: {
    parameters: {
      query?: never
      header?: never
      path?: never
      cookie?: never
    }
    requestBody: {
      content: {
        'multipart/form-data': {
          /** @example My cool track */
          title: string
          /** Format: binary */
          file: string
        }
      }
    }
    responses: {
      /** @description OK: Track created successfully */
      200: {
        headers: {
          [name: string]: unknown
        }
        content: {
          'application/json': components['schemas']['GetTrackDetailsOutput']
        }
      }
      /** @description Bad Request: Invalid file format or file size exceeded */
      400: {
        headers: {
          [name: string]: unknown
        }
        content?: never
      }
      /** @description Internal Server Error: Error saving file or track */
      500: {
        headers: {
          [name: string]: unknown
        }
        content?: never
      }
    }
  }
  ArtistsController_createArtist: {
    parameters: {
      query?: never
      header?: never
      path?: never
      cookie?: never
    }
    requestBody: {
      content: {
        'application/json': components['schemas']['CreateArtistRequestPayload']
      }
    }
    responses: {
      /** @description Created: Artist created successfully */
      201: {
        headers: {
          [name: string]: unknown
        }
        content: {
          'application/json': components['schemas']['ArtistRef']
        }
      }
      /** @description Bad Request: Validation error or invalid input */
      400: {
        headers: {
          [name: string]: unknown
        }
        content?: never
      }
      /** @description Unauthorized: User not authenticated */
      401: {
        headers: {
          [name: string]: unknown
        }
        content?: never
      }
      /** @description Forbidden: Limit of 100 artists per user reached */
      403: {
        headers: {
          [name: string]: unknown
        }
        content?: never
      }
      /** @description Conflict: Artist with the given name already exists */
      409: {
        headers: {
          [name: string]: unknown
        }
        content?: never
      }
    }
  }
  ArtistsController_searchArtist: {
    parameters: {
      query: {
        search: string
      }
      header?: never
      path?: never
      cookie?: never
    }
    requestBody?: never
    responses: {
      /** @description OK: List of artists matching the search */
      200: {
        headers: {
          [name: string]: unknown
        }
        content: {
          'application/json': components['schemas']['ArtistRef'][]
        }
      }
    }
  }
  ArtistsController_deleteArtist: {
    parameters: {
      query?: never
      header?: never
      path: {
        id: string
      }
      cookie?: never
    }
    requestBody?: never
    responses: {
      /** @description No Content: Artist deleted successfully */
      204: {
        headers: {
          [name: string]: unknown
        }
        content?: never
      }
      /** @description Forbidden: Artist is attached to tracks or was created by another user */
      403: {
        headers: {
          [name: string]: unknown
        }
        content?: never
      }
      /** @description Not Found: Artist with the specified ID not found */
      404: {
        headers: {
          [name: string]: unknown
        }
        content?: never
      }
    }
  }
  AuthController_OauthRedirect: {
    parameters: {
      query: {
        /** @description The callback URL to redirect after grand access,
         *          https://oauth.apihub.it-incubator.io/realms/apihub/protocol/openid-connect/auth?client_id=musicfun&response_type=code&redirect_uri=http://localhost:3000/oauth2/callback&scope=openid */
        callbackUrl: string
      }
      header?: never
      path?: never
      cookie?: never
    }
    requestBody?: never
    responses: {
      /** @description OK: Redirect executed successfully */
      200: {
        headers: {
          [name: string]: unknown
        }
        content?: never
      }
    }
  }
  AuthController_login: {
    parameters: {
      query?: never
      header?: never
      path?: never
      cookie?: never
    }
    requestBody: {
      content: {
        'application/json': components['schemas']['LoginRequestPayload']
      }
    }
    responses: {
      /** @description OK: Token pair retrieved successfully */
      200: {
        headers: {
          [name: string]: unknown
        }
        content: {
          'application/json': components['schemas']['RefreshOutput']
        }
      }
      /** @description Bad Request: Invalid request format or required parameters are missing */
      400: {
        headers: {
          [name: string]: unknown
        }
        content: {
          'application/json': components['schemas']['BadRequestException']
        }
      }
      /** @description Unauthorized: Code is invalid, expired, missing, or redirectUri does not match */
      401: {
        headers: {
          [name: string]: unknown
        }
        content: {
          'application/json': components['schemas']['UnauthorizedException']
        }
      }
    }
  }
  AuthController_refresh: {
    parameters: {
      query?: never
      header?: never
      path?: never
      cookie?: never
    }
    requestBody: {
      content: {
        'application/json': components['schemas']['RefreshRequestPayload']
      }
    }
    responses: {
      /** @description OK: Token pair refreshed successfully */
      200: {
        headers: {
          [name: string]: unknown
        }
        content: {
          'application/json': components['schemas']['RefreshOutput']
        }
      }
      /** @description Unauthorized: Refresh token is invalid, expired, or missing */
      401: {
        headers: {
          [name: string]: unknown
        }
        content: {
          'application/json': components['schemas']['UnauthorizedException']
        }
      }
    }
  }
  AuthController_logout: {
    parameters: {
      query?: never
      header?: never
      path?: never
      cookie?: never
    }
    requestBody: {
      content: {
        'application/json': components['schemas']['LogoutRequestPayload']
      }
    }
    responses: {
      /** @description No Content: Refresh token deactivated; access token remains valid. */
      204: {
        headers: {
          [name: string]: unknown
        }
        content?: never
      }
    }
  }
  AuthController_getMe: {
    parameters: {
      query?: never
      header?: never
      path?: never
      cookie?: never
    }
    requestBody?: never
    responses: {
      /** @description OK: Successfully retrieved user information */
      200: {
        headers: {
          [name: string]: unknown
        }
        content: {
          'application/json': components['schemas']['GetMeOutput']
        }
      }
      /** @description Unauthorized: access token is missing or invalid */
      401: {
        headers: {
          [name: string]: unknown
        }
        content?: never
      }
    }
  }
  TagsController_createTag: {
    parameters: {
      query?: never
      header?: never
      path?: never
      cookie?: never
    }
    requestBody: {
      content: {
        'application/json': components['schemas']['CreateTagRequestPayload']
      }
    }
    responses: {
      /** @description Created: Tag created successfully */
      201: {
        headers: {
          [name: string]: unknown
        }
        content: {
          'application/json': components['schemas']['TagRef']
        }
      }
      /** @description Bad Request: Validation error */
      400: {
        headers: {
          [name: string]: unknown
        }
        content?: never
      }
      /** @description Unauthorized: User not authenticated */
      401: {
        headers: {
          [name: string]: unknown
        }
        content?: never
      }
      /** @description Forbidden: Limit of 100 tags per user reached */
      403: {
        headers: {
          [name: string]: unknown
        }
        content?: never
      }
      /** @description Conflict: Tag with the given name already exists */
      409: {
        headers: {
          [name: string]: unknown
        }
        content?: never
      }
    }
  }
  TagsController_searchTags: {
    parameters: {
      query: {
        /** @description Substring to search tags by (using normalized name) */
        search: string
      }
      header?: never
      path?: never
      cookie?: never
    }
    requestBody?: never
    responses: {
      /** @description OK: List of matching tags */
      200: {
        headers: {
          [name: string]: unknown
        }
        content: {
          'application/json': components['schemas']['TagRef'][]
        }
      }
      /** @description Bad Request: Invalid search query */
      400: {
        headers: {
          [name: string]: unknown
        }
        content?: never
      }
    }
  }
  TagsController_deleteTag: {
    parameters: {
      query?: never
      header?: never
      path: {
        /** @description ID of the tag to delete */
        id: string
      }
      cookie?: never
    }
    requestBody?: never
    responses: {
      /** @description No Content: Tag deleted successfully */
      204: {
        headers: {
          [name: string]: unknown
        }
        content?: never
      }
      /** @description Unauthorized: User not authenticated */
      401: {
        headers: {
          [name: string]: unknown
        }
        content?: never
      }
      /** @description Forbidden: Tag was created by another user or is attached to tracks or playlists */
      403: {
        headers: {
          [name: string]: unknown
        }
        content?: never
      }
      /** @description Not Found: Tag with the specified ID not found */
      404: {
        headers: {
          [name: string]: unknown
        }
        content?: never
      }
    }
  }
}
export enum PathsPlaylistsGetParametersQuerySortBy {
  addedAt = 'addedAt',
  likesCount = 'likesCount',
}
export enum PathsPlaylistsGetParametersQuerySortDirection {
  asc = 'asc',
  desc = 'desc',
}
export enum PathsPlaylistsTracksGetParametersQuerySortBy {
  publishedAt = 'publishedAt',
  likesCount = 'likesCount',
}
export enum PathsPlaylistsTracksGetParametersQueryPaginationType {
  offset = 'offset',
  cursor = 'cursor',
}
export enum ImageSizeType {
  original = 'original',
  thumbnail = 'thumbnail',
  medium = 'medium',
}
export enum ReactionValue {
  Value0 = 0,
  Value1 = 1,
  ValueMinus1 = -1,
}


================================================
FILE: apps/react-effector-fsd/src/shared/api/utils/json-api-error.ts
================================================
export interface JsonApiError {
  status: string
  code?: string | number
  title?: string
  detail?: string
  source?: { pointer?: string; parameter?: string }
  meta?: Record<string, unknown>
}

export interface JsonApiErrorDocument {
  errors: JsonApiError[]
  meta?: Record<string, unknown>
}

export type ExtractError<T> = T extends { error?: infer E } ? E : unknown

/* --- типы ошибок, совпадающие с фильтром -------------------------------- */
export interface JsonApiError {
  status: string
  code?: string | number
  title?: string
  detail?: string
  source?: { pointer?: string; parameter?: string }
  meta?: Record<string, unknown>
}

export interface JsonApiErrorDocument {
  errors: JsonApiError[]
  meta?: Record<string, unknown>
}

export function isJsonApiErrorDocument(error: unknown): error is JsonApiErrorDocument {
  return (
    typeof error === 'object' &&
    error !== null &&
    // @ts-expect-error type no matter
    Array.isArray(error.errors)
  )
}

export function parseJsonApiErrors(errorDoc: JsonApiErrorDocument): {
  fieldErrors: Record<string, string>
  globalErrors: string[]
} {
  const fieldErrors: Record<string, string> = {}
  const globalErrors: string[] = []

  for (const err of errorDoc.errors) {
    const msg = err.detail ?? err.title ?? 'Unknown error'
    const ptr = err.source?.pointer
    if (ptr) {
      // убираем префикс JSON:API
      const field = ptr.replace(/^\/data\/attributes\//, '')
      fieldErrors[field] = msg
    } else {
      globalErrors.push(msg)
    }
  }

  return { fieldErrors, globalErrors }
}


================================================
FILE: apps/react-effector-fsd/src/shared/api/utils/request-wrapper.ts
================================================
// types/api.ts

import { type ExtractError } from './json-api-error.ts'

//-----------------------------------------------------------------------------
// utils/requestWrapper.ts
//-----------------------------------------------------------------------------
// «Умный» обёртчик: Infers Data и Error из P,
// возвращает Promise<Data>, а в случае ошибки — throw Error
export type ExtractData<T> = T extends { data?: infer D } ? NonNullable<D> : never

export async function requestWrapper<P extends Promise<{ data?: unknown; error?: unknown }>>(
  promise: P
): Promise<ExtractData<Awaited<P>>> {
  const res = (await promise) as Awaited<P>
  if ((res as { error?: unknown }).error) {
    // здесь E = ExtractError<Awaited<P>>
    throw (res as { error: ExtractError<Awaited<P>> }).error
  }
  return (res as { data: ExtractData<Awaited<P>> }).data
}


================================================
FILE: apps/react-effector-fsd/src/shared/components/AudioPlayer/AudioPlayer.module.css
================================================
.player {
  display: flex;
  gap: 16px;
  align-items: center;
  justify-content: space-between;

  width: 100%;
  min-height: 64px;

  background: var(--color-bg-primary);
}

.trackInfo {
  display: flex;
  gap: 12px;
  align-items: center;
  min-width: 200px;
}

.cover {
  width: 112px;
  height: 112px;
  border-radius: 4px;
  background: var(--color-bg-card);
}

.cover img {
  width: 100%;
  height: 100%;
  object-fit: cover;
}

.info {
  display: flex;
  flex-direction: column;
  gap: 2px;
}

.playerControls {
  display: flex;
  flex: 1;
  flex-direction: column;
  gap: 8px;
  align-items: center;
}

.controls {
  display: flex;
  gap: 16px;
  align-items: center;
}

.playPauseButton {
  width: 48px;
  height: 48px;
}

.active {
  color: var(--color-accent);
}

.iconButton.active:hover,
.iconButton.active:focus {
  color: var(--color-accent);
}

.progressBar {
  display: flex;
  gap: 8px;
  align-items: center;

  width: 100%;
  max-width: 632px;
}

.time {
  min-width: 36px;
  font-size: var(--font-size-xs);
  color: var(--color-text-secondary);
  text-align: center;
}

.progress {
  cursor: pointer;

  height: 5px;
  border: none;
  border-radius: 4px;

  accent-color: var(--color-text-primary);
}

.trackProgress {
  width: 100%;
  max-width: 550px;
}

.volumeColumn {
  display: flex;
  align-items: center;
  justify-content: flex-end;

  min-width: 160px;
  padding-right: 32px;
}

.volumeProgress {
  width: 119px;
}


================================================
FILE: apps/react-effector-fsd/src/shared/components/AudioPlayer/AudioPlayer.stories.tsx
================================================
import type { Meta } from '@storybook/react-vite'
import { useState } from 'react'

import { AudioPlayer } from './AudioPlayer.tsx'

const meta = {
  title: 'Components/Player',
  component: AudioPlayer,
  parameters: {},
  args: {},
} satisfies Meta<typeof AudioPlayer>

export default meta

const demoTrack = {
  src: 'https://cdn.uppbeat.io/audio-files/c636d7c86452449b1203fc0bded83e29/4358717fc9da477a52fb18a6cbd3afcc/d154b5ce5ff1a05ae8115a3c678062e8/STREAMING-dreamland-matrika-main-version-31140-02-25.mp3',
  cover: 'https://unsplash.it/112/112',
  title: 'Play It Safe',
  artist: 'Julia Wolf',
}

export const Basic = {
  render: () => {
    const [isPlaying, setIsPlaying] = useState(false)
    const [isShuffle, setIsShuffle] = useState(false)
    const [isRepeat, setIsRepeat] = useState(false)

    const [track] = useState(demoTrack)
    return (
      <AudioPlayer
        {...track}
        isPlaying={isPlaying}
        setIsPlaying={setIsPlaying}
        onNext={() => {}}
        onPrevious={() => {}}
        isShuffle={isShuffle}
        isRepeat={isRepeat}
        onShuffle={() => setIsShuffle(!isShuffle)}
        onRepeat={() => setIsRepeat(!isRepeat)}
      />
    )
  },
}


================================================
FILE: apps/react-effector-fsd/src/shared/components/AudioPlayer/AudioPlayer.tsx
================================================
import { clsx } from 'clsx'
import { type ComponentProps, useRef, useState } from 'react'

import {
  PauseIcon,
  PlayIcon,
  RepeatIcon,
  ShuffleIcon,
  SkipNextIcon,
  SkipPreviousIcon,
  VolumeIcon,
  VolumeMuteIcon,
} from '@/shared/icons'

import { IconButton } from '../IconButton'
import { Typography } from '../Typography'
import s from './AudioPlayer.module.css'

export type PlayerProps = {
  src: string
  cover: string
  title: string
  artist: string
  isPlaying: boolean
  setIsPlaying: (isPlaying: boolean) => void
  onNext: () => void
  onPrevious: () => void
  isShuffle: boolean
  isRepeat: boolean
  onShuffle: () => void
  onRepeat: () => void
} & ComponentProps<'div'>

export const AudioPlayer = ({
  src,
  cover,
  title,
  artist,
  isPlaying,
  setIsPlaying,
  onNext,
  onPrevious,
  isShuffle,
  isRepeat,
  onShuffle,
  onRepeat,
  className,
  ...props
}: PlayerProps) => {
  const audioRef = useRef<HTMLAudioElement | null>(null)
  const [currentTime, setCurrentTime] = useState(0)
  const [volume, setVolume] = useState(1)
  const [duration, setDuration] = useState(0)

  const handlePlayPause = () => {
    const audio = audioRef.current
    if (!audio) return

    if (isPlaying) {
      audio.pause()
    } else {
      audio.play().catch((e) => {
        console.error('Audio play error:', e)
      })
    }

    setIsPlaying(!isPlaying)
  }

  const handleChangeTime = (e: React.ChangeEvent<HTMLInputElement>) => {
    const time = Number(e.target.value)
    setCurrentTime(time)
    if (audioRef.current) {
      audioRef.current.currentTime = time
    }
  }

  const handleVolume = (e: React.ChangeEvent<HTMLInputElement>) => {
    const newVolume = Number(e.target.value)
    setVolume(newVolume)
    if (audioRef.current) {
      audioRef.current.volume = newVolume
    }
  }

  const handleVolumeMute = () => {
    const newVolume = volume > 0 ? 0 : 1
    setVolume(newVolume)
    if (audioRef.current) {
      audioRef.current.volume = newVolume
    }
  }

  return (
    <div className={clsx(s.player, className)} {...props}>
      <audio
        ref={audioRef}
        src={src}
        onTimeUpdate={(e) => setCurrentTime(e.currentTarget.currentTime)}
        onLoadedMetadata={(e) => setDuration(e.currentTarget.duration)}
      />

      <div className={s.trackInfo}>
        <div className={s.cover}>
          <img src={cover} alt="cover" />
        </div>
        <div className={s.info}>
          <Typography variant="body1" as="h3">
            {title}
          </Typography>
          <Typography variant="body2" as="p">
            {artist}
          </Typography>
        </div>
      </div>

      <div className={s.playerControls}>
        <div className={s.controls}>
          <IconButton onClick={onShuffle} className={clsx(s.iconButton, isShuffle && s.active)}>
            <ShuffleIcon />
          </IconButton>
          <IconButton onClick={onPrevious}>
            <SkipPreviousIcon />
          </IconButton>
          <IconButton className={s.playPauseButton} onClick={handlePlayPause}>
            {isPlaying ? <PauseIcon /> : <PlayIcon />}
          </IconButton>
          <IconButton onClick={onNext}>
            <SkipNextIcon />
          </IconButton>
          <IconButton onClick={onRepeat} className={clsx(s.iconButton, isRepeat && s.active)}>
            <RepeatIcon />
          </IconButton>
        </div>

        <div className={s.progressBar}>
          <span className={s.time}>{format(currentTime)}</span>
          <input
            type="range"
            min={0}
            max={duration}
            value={currentTime}
            onChange={handleChangeTime}
            className={clsx(s.progress, s.trackProgress)}
          />
          <span className={s.time}>{format(duration)}</span>
        </div>
      </div>

      <div className={s.volumeColumn}>
        <IconButton onClick={handleVolumeMute}>
          {volume > 0 ? <VolumeIcon /> : <VolumeMuteIcon />}
        </IconButton>
        <input
          type="range"
          min={0}
          max={1}
          step={0.01}
          value={volume}
          onChange={handleVolume}
          className={clsx(s.progress, s.volumeProgress)}
        />
      </div>
    </div>
  )
}

const format = (sec: number) => {
  const m = Math.floor(sec / 60)
  const s = Math.floor(sec % 60)
  return `${m}:${s.toString().padStart(2, '0')}`
}


================================================
FILE: apps/react-effector-fsd/src/shared/components/AudioPlayer/index.ts
================================================
export * from './AudioPlayer.tsx'


================================================
FILE: apps/react-effector-fsd/src/shared/components/Autocomplete/Autocomplete.module.css
================================================
.container {
  position: relative;
  display: flex;
  flex-direction: column;
  width: 100%;
}

.label {
  font-size: var(--font-size-s);
  line-height: 1.7;
  color: var(--color-text-label);
}

.labelError {
  color: var(--color-text-error);
}

.inputWrapper {
  position: relative;

  display: flex;
  flex-wrap: wrap;
  gap: 6px;
  align-items: center;

  min-height: 48px;
  padding: 4px 8px;
  border: 1px solid var(--color-border-input-primary);
  border-radius: 4px;

  background-color: var(--color-bg-primary);

  transition: all 200ms ease;
}

.inputWrapper:hover:not(.disabled) {
  background-color: var(--color-bg-input-hover);
}

.inputWrapper.focused {
  border-color: var(--color-border-input-active);
  background-color: var(--color-bg-primary);
}

.inputWrapper.error {
  border-color: var(--color-text-error);
}

.inputWrapper.disabled {
  cursor: not-allowed;
  background-color: var(--color-disabled);
}

.tag {
  display: flex;
  gap: 4px;
  align-items: center;

  padding: 2px 6px;
  border: 1px solid var(--color-border-base);
  border-radius: 16px;

  background-color: var(--color-bg-secondary);

  transition: all 200ms ease;
}

.tag:hover {
  background-color: var(--color-bg-input-hover);
}

.tagText {
  font-size: var(--font-size-s);
  font-weight: 500;
  color: var(--color-text-primary);
  white-space: nowrap;
}

.deleteButton {
  width: 16px;
  height: 16px;
  padding: 0;

  font-size: 10px;
  color: var(--color-text-secondary);

  background: transparent;

  transition: all 200ms ease;
}

.deleteButton:hover {
  color: var(--color-text-error);
  background-color: transparent;
}

.inputContainer {
  position: relative;

  display: flex;
  flex: 1;
  align-items: center;

  min-width: 120px;
}

.searchIcon {
  pointer-events: none;

  position: absolute;
  z-index: 1;
  left: 4px;

  width: 16px;
  height: 16px;

  color: var(--color-text-secondary);

  transition: color 200ms ease;
}

.input {
  width: 100%;
  padding: 4px 8px 4px 24px;
  border: none;

  font-size: var(--font-size-m);
  color: var(--color-text-primary);

  background: transparent;
  outline: none;

  transition: all 200ms ease;
}

.input::placeholder {
  color: var(--color-text-secondary);
}

.input:disabled {
  cursor: not-allowed;
  color: var(--color-disabled);
}

.dropdownIcon {
  cursor: pointer;

  width: 20px;
  height: 20px;
  margin-left: 4px;

  color: var(--color-text-secondary);

  transition: transform 200ms ease;
}

.dropdownIcon:hover {
  color: var(--color-text-primary);
}

.dropdownIconOpen {
  transform: rotate(180deg);
}

.dropdown {
  position: absolute;
  z-index: 50;
  top: 100%;
  left: 0;

  overflow-y: auto;

  width: 100%;
  max-height: 200px;
  margin-top: 4px;
  padding: 4px;
  border: 1px solid var(--color-border-base);
  border-radius: 4px;

  background-color: var(--color-bg-primary);
  box-shadow:
    0 10px 38px -10px rgb(22 23 24 / 35%),
    0 10px 20px -15px rgb(22 23 24 / 20%);

  animation: dropdown-show 200ms ease-out;
}

.option {
  cursor: pointer;

  display: flex;
  align-items: center;

  padding: 8px 12px;
  border-radius: 4px;

  transition: all 200ms ease;
}

.option:hover:not(.optionDisabled) {
  background-color: var(--color-bg-input-hover);
}

.optionFocused:not(.optionDisabled) {
  color: var(--color-bg-primary);
  background-color: var(--color-accent);
}

.optionDisabled {
  cursor: not-allowed;
  opacity: 0.5;
}

.noResults {
  padding: 12px;
  text-align: center;
}

.noResultsText {
  color: var(--color-text-secondary);
}

.errorMessage {
  margin-top: 4px;
  font-size: var(--font-size-s);
  color: var(--color-text-error);
}

.counter {
  margin-top: 4px;
  color: var(--color-text-secondary);
}

/* Animations */
@keyframes dropdown-show {
  from {
    transform: translateY(-4px);
    opacity: 0;
  }

  to {
    transform: translateY(0);
    opacity: 1;
  }
}


================================================
FILE: apps/react-effector-fsd/src/shared/components/Autocomplete/Autocomplete.stories.tsx
================================================
import type { Meta, StoryObj } from '@storybook/react-vite'
import { useState } from 'react'

import { Button } from '../Button'
import { Card } from '../Card'
import { Dialog, DialogContent, DialogFooter, DialogHeader } from '../Dialog'
import { Typography } from '../Typography'
import { Autocomplete, type AutocompleteOption } from './Autocomplete'

const meta = {
  title: 'Components/Autocomplete',
  component: Autocomplete,
  parameters: {
    layout: 'centered',
  },
  args: {},
} satisfies Meta<typeof Autocomplete>

export default meta
type Story = StoryObj<typeof meta>

// Sample data
const programmingLanguages: AutocompleteOption[] = [
  { value: 'javascript', label: 'JavaScript' },
  { value: 'typescript', label: 'TypeScript' },
  { value: 'python', label: 'Python' },
  { value: 'java', label: 'Java' },
  { value: 'cpp', label: 'C++' },
  { value: 'csharp', label: 'C#' },
  { value: 'php', label: 'PHP' },
  { value: 'ruby', label: 'Ruby' },
  { value: 'go', label: 'Go' },
  { value: 'rust', label: 'Rust' },
  { value: 'kotlin', label: 'Kotlin' },
  { value: 'swift', label: 'Swift' },
]

const musicGenres: AutocompleteOption[] = [
  { value: 'rock', label: 'Rock' },
  { value: 'pop', label: 'Pop' },
  { value: 'jazz', label: 'Jazz' },
  { value: 'classical', label: 'Classical' },
  { value: 'electronic', label: 'Electronic' },
  { value: 'hiphop', label: 'Hip Hop' },
  { value: 'country', label: 'Country' },
  { value: 'blues', label: 'Blues' },
  { value: 'reggae', label: 'Reggae' },
  { value: 'folk', label: 'Folk' },
  { value: 'metal', label: 'Metal' },
  { value: 'indie', label: 'Indie' },
]

const skills: AutocompleteOption[] = [
  { value: 'frontend', label: 'Frontend Development' },
  { value: 'backend', label: 'Backend Development' },
  { value: 'fullstack', label: 'Full Stack Development' },
  { value: 'mobile', label: 'Mobile Development' },
  { value: 'devops', label: 'DevOps' },
  { value: 'testing', label: 'Testing & QA' },
  { value: 'design', label: 'UI/UX Design' },
  { value: 'pm', label: 'Project Management', disabled: true },
  { value: 'data', label: 'Data Science' },
  { value: 'ml', label: 'Machine Learning' },
]

export const Basic = {
  render: () => {
    const [selectedValues, setSelectedValues] = useState<string[]>([])

    return (
      <div style={{ width: '400px' }}>
        <Autocomplete
          label="Programming Languages"
          placeholder="Search and select languages..."
          options={programmingLanguages}
          value={selectedValues}
          onChange={setSelectedValues}
        />
      </div>
    )
  },
}

export const WithMaxTags = {
  render: () => {
    const [selectedValues, setSelectedValues] = useState<string[]>([])

    return (
      <div style={{ width: '400px' }}>
        <Autocomplete
          label="Music Genres (max 3)"
          placeholder="Choose up to 3 genres..."
          options={musicGenres}
          value={selectedValues}
          onChange={setSelectedValues}
          maxTags={3}
        />
      </div>
    )
  },
}

export const WithPreselected = {
  render: () => {
    const [selectedValues, setSelectedValues] = useState<string[]>(['javascript', 'typescript'])

    return (
      <div style={{ width: '400px' }}>
        <Autocomplete
          label="Your Skills"
          placeholder="Add more skills..."
          options={programmingLanguages}
          value={selectedValues}
          onChange={setSelectedValues}
        />
      </div>
    )
  },
}

export const WithDisabledOptions = {
  render: () => {
    const [selectedValues, setSelectedValues] = useState<string[]>([])

    return (
      <div style={{ width: '400px' }}>
        <Autocomplete
          label="Skills & Roles"
          placeholder="Select your skills..."
          options={skills}
          value={selectedValues}
          onChange={setSelectedValues}
        />
      </div>
    )
  },
}

export const Disabled = {
  render: () => {
    const [selectedValues, setSelectedValues] = useState<string[]>(['rock', 'jazz'])

    return (
      <div style={{ width: '400px' }}>
        <Autocomplete
          label="Music Genres (disabled)"
          placeholder="Cannot select"
          options={musicGenres}
          value={selectedValues}
          onChange={setSelectedValues}
          disabled
        />
      </div>
    )
  },
}

export const WithError = {
  render: () => {
    const [selectedValues, setSelectedValues] = useState<string[]>([])

    return (
      <div style={{ width: '400px' }}>
        <Autocomplete
          label="Required Skills"
          placeholder="Select at least one skill..."
          options={programmingLanguages}
          value={selectedValues}
          onChange={setSelectedValues}
          errorMessage="Please select at least one programming language"
        />
      </div>
    )
  },
}

export const Interactive = {
  render: () => {
    const [frontendSkills, setFrontendSkills] = useState<string[]>(['javascript'])
    const [backendSkills, setBackendSkills] = useState<string[]>([])
    const [genres, setGenres] = useState<string[]>([])

    const frontendOptions: AutocompleteOption[] = [
      { value: 'html', label: 'HTML' },
      { value: 'css', label: 'CSS' },
      { value: 'javascript', label: 'JavaScript' },
      { value: 'typescript', label: 'TypeScript' },
      { value: 'react', label: 'React' },
      { value: 'vue', label: 'Vue.js' },
      { value: 'angular', label: 'Angular' },
      { value: 'svelte', label: 'Svelte' },
    ]

    const backendOptions: AutocompleteOption[] = [
      { value: 'nodejs', label: 'Node.js' },
      { value: 'python', label: 'Python' },
      { value: 'java', label: 'Java' },
      { value: 'csharp', label: 'C#' },
      { value: 'php', label: 'PHP' },
      { value: 'ruby', label: 'Ruby' },
      { value: 'go', label: 'Go' },
      { value: 'rust', label: 'Rust' },
    ]

    return (
      <div
        style={{
          width: '500px',
          display: 'flex',
          flexDirection: 'column',
          gap: '24px',
        }}>
        <div>
          <Typography variant="h3" style={{ marginBottom: '16px' }}>
            Developer Profile Setup
          </Typography>
        </div>

        <Autocomplete
          label="Frontend Technologies"
          placeholder="Select frontend skills..."
          options={frontendOptions}
          value={frontendSkills}
          onChange={setFrontendSkills}
          maxTags={5}
        />

        <Autocomplete
          label="Backend Technologies"
          placeholder="Select backend skills..."
          options={backendOptions}
          value={backendSkills}
          onChange={setBackendSkills}
          maxTags={4}
        />

        <Autocomplete
          label="Favorite Music Genres"
          placeholder="What music do you like?"
          options={musicGenres}
          value={genres}
          onChange={setGenres}
          maxTags={6}
        />

        <Card style={{ padding: '16px' }}>
          <Typography variant="h3" style={{ marginBottom: '12px' }}>
            Profile Summary
          </Typography>

          <div style={{ display: 'flex', flexDirection: 'column', gap: '8px' }}>
            <Typography variant="body2">
              <strong>Frontend:</strong>{' '}
              {frontendSkills.length > 0 ? frontendSkills.join(', ') : 'None'}
            </Typography>
            <Typography variant="body2">
              <strong>Backend:</strong>{' '}
              {backendSkills.length > 0 ? backendSkills.join(', ') : 'None'}
            </Typography>
            <Typography variant="body2">
              <strong>Music:</strong> {genres.length > 0 ? genres.join(', ') : 'None'}
            </Typography>
          </div>
        </Card>
      </div>
    )
  },
}

export const AllStates = {
  render: () => {
    const [state1, setState1] = useState<string[]>([])
    const [state2, setState2] = useState<string[]>(['rock', 'jazz'])
    const [state3, setState3] = useState<string[]>([])
    const [state4, setState4] = useState<string[]>(['javascript'])

    return (
      <div
        style={{
          width: '600px',
          display: 'flex',
          flexDirection: 'column',
          gap: '32px',
        }}>
        <div>
          <Typography variant="h3" style={{ marginBottom: '12px' }}>
            Empty State
          </Typography>
          <Autocomplete
            label="Programming Languages"
            placeholder="Start typing to search..."
            options={programmingLanguages}
            value={state1}
            onChange={setState1}
          />
        </div>

        <div>
          <Typography variant="h3" style={{ marginBottom: '12px' }}>
            With Selected Values
          </Typography>
          <Autocomplete
            label="Music Genres"
            placeholder="Add more genres..."
            options={musicGenres}
            value={state2}
            onChange={setState2}
          />
        </div>

        <div>
          <Typography variant="h3" style={{ marginBottom: '12px' }}>
            With Error
          </Typography>
          <Autocomplete
            label="Required Field"
            placeholder="This field is required"
            options={programmingLanguages}
            value={state3}
            onChange={setState3}
            errorMessage="Please select at least one option"
          />
        </div>

        <div>
          <Typography variant="h3" style={{ marginBottom: '12px' }}>
            Disabled State
          </Typography>
          <Autocomplete
            label="Locked Selection"
            placeholder="Cannot modify"
            options={programmingLanguages}
            value={state4}
            onChange={setState4}
            disabled
          />
        </div>
      </div>
    )
  },
}

export const InDialog = {
  render: () => {
    const [isOpen, setIsOpen] = useState(false)
    const [selectedSkills, setSelectedSkills] = useState<string[]>([])
    const [selectedGenres, setSelectedGenres] = useState<string[]>(['rock'])

    const handleSubmit = () => {
      console.log('Selected skills:', selectedSkills)
      console.log('Selected genres:', selectedGenres)
      setIsOpen(false)
    }

    const handleReset = () => {
      setSelectedSkills([])
      setSelectedGenres([])
    }

    return (
      <>
        <Button onClick={() => setIsOpen(true)}>Open Profile Settings</Button>

        <Dialog open={isOpen} onClose={() => setIsOpen(false)}>
          <DialogHeader>
            <Typography variant="h2">Edit Your Profile</Typography>
            <Typography variant="body2" style={{ color: 'var(--color-text-secondary)' }}>
              Update your skills and music preferences
            </Typography>
          </DialogHeader>

          <DialogContent>
            <div
              style={{
                display: 'flex',
                flexDirection: 'column',
                gap: '24px',
                minWidth: '400px',
              }}>
              <Autocomplete
                label="Technical Skills"
                placeholder="Search and select your skills..."
                options={skills}
                value={selectedSkills}
                onChange={setSelectedSkills}
                maxTags={8}
              />

              <Autocomplete
                label="Favorite Music Genres"
                placeholder="What music do you enjoy?"
                options={musicGenres}
                value={selectedGenres}
                onChange={setSelectedGenres}
                maxTags={5}
              />
            </div>
          </DialogContent>

          <DialogFooter>
            <Button variant="secondary" onClick={handleReset}>
              Reset All
            </Button>
            <Button variant="secondary" onClick={() => setIsOpen(false)}>
              Cancel
            </Button>
            <Button variant="primary" onClick={handleSubmit}>
              Save Profile
            </Button>
          </DialogFooter>
        </Dialog>
      </>
    )
  },
}


================================================
FILE: apps/react-effector-fsd/src/shared/components/Autocomplete/Autocomplete.tsx
================================================
import { clsx } from 'clsx'
import {
  type ComponentProps,
  type KeyboardEvent,
  type ReactNode,
  useEffect,
  useRef,
  useState,
} from 'react'

import { useGetId } from '@/shared/hooks'
import { ArrowDownIcon, DeleteIcon } from '@/shared/icons'

import { IconButton } from '../IconButton'
import { Typography } from '../Typography'
import s from './Autocomplete.module.css'

export type AutocompleteOption = {
  value: string
  label: string
  disabled?: boolean
}

export type AutocompleteProps = {
  label?: ReactNode
  placeholder?: string
  options: AutocompleteOption[]
  value: string[]
  onChange: (value: string[]) => void
  disabled?: boolean
  maxTags?: number
  errorMessage?: string
  className?: string
} & Omit<ComponentProps<'div'>, 'onChange'>

export const Autocomplete = ({
  label,
  placeholder = 'Search and select...',
  options,
  value,
  onChange,
  disabled = false,
  maxTags,
  errorMessage,
  className,
  ...props
}: AutocompleteProps) => {
  const [isOpen, setIsOpen] = useState(false)
  const [searchTerm, setSearchTerm] = useState('')
  const [focusedIndex, setFocusedIndex] = useState(-1)

  // For detecting clicks outside component to close dropdown
  const containerRef = useRef<HTMLDivElement>(null)
  // For programmatic focus management (Escape key, focus after selection)
  const inputRef = useRef<HTMLInputElement>(null)

  const id = useGetId(props.id)

  const filteredOptions = options.filter(
    (option) =>
      option.label.toLowerCase().includes(searchTerm.toLowerCase()) && !value.includes(option.value)
  )

  const isMaxTagsReached = maxTags ? value.length >= maxTags : false
  const showError = Boolean(errorMessage)

  // Close dropdown on outside click
  useEffect(() => {
    if (!isOpen) return

    const handleClickOutside = (e: MouseEvent) => {
      if (containerRef.current && !containerRef.current.contains(e.target as Node)) {
        setIsOpen(false)
        setFocusedIndex(-1)
      }
    }

    document.addEventListener('mousedown', handleClickOutside)
    return () => document.removeEventListener('mousedown', handleClickOutside)
  }, [isOpen])

  // Handle keyboard navigation
  const handleKeyDown = (e: KeyboardEvent<HTMLInputElement>) => {
    if (disabled) return

    switch (e.key) {
      case 'ArrowDown':
        e.preventDefault()
        if (!isOpen) {
          setIsOpen(true)
          setFocusedIndex(0)
        } else {
          setFocusedIndex((prev) => (prev < filteredOptions.length - 1 ? prev + 1 : prev))
        }
        break

      case 'ArrowUp':
        e.preventDefault()
        setFocusedIndex((prev) => (prev > 0 ? prev - 1 : 0))
        break

      case 'Enter':
        e.preventDefault()
        if (isOpen && focusedIndex >= 0 && filteredOptions[focusedIndex]) {
          selectOption(filteredOptions[focusedIndex])
        }
        break

      case 'Escape':
        e.preventDefault()
        setIsOpen(false)
        setFocusedIndex(-1)
        inputRef.current?.blur()
        break

      case 'Backspace':
        if (!searchTerm && value.length > 0) {
          removeTag(value[value.length - 1])
        }
        break
    }
  }

  const selectOption = (option: AutocompleteOption) => {
    if (option.disabled || isMaxTagsReached) return

    onChange([...value, option.value])
    setSearchTerm('')
    setFocusedIndex(-1)
    inputRef.current?.focus()
  }

  const removeTag = (tagValue: string) => {
    onChange(value.filter((v) => v !== tagValue))
  }

  const handleInputFocus = () => {
    if (!disabled) {
      setIsOpen(true)
    }
  }

  const handleInputChange = (e: React.ChangeEvent<HTMLInputElement>) => {
    setSearchTerm(e.target.value)
    setIsOpen(true)
    setFocusedIndex(-1)
  }

  const selectedOptions = options.filter((option) => value.includes(option.value))

  return (
    <div className={clsx(s.container, className)} ref={containerRef} {...props}>
      {label && (
        <Typography
          variant="label"
          className={clsx(s.label, showError && s.labelError)}
          as="label"
          htmlFor={id}>
          {label}
        </Typography>
      )}

      <div
        className={clsx(
          s.inputWrapper,
          isOpen && s.focused,
          showError && s.error,
          disabled && s.disabled
        )}>
        {/* Selected tags */}
        {selectedOptions.map((option) => (
          <div key={option.value} className={s.tag}>
            <Typography variant="body2" className={s.tagText} as="label">
              {option.label}
            </Typography>
            {!disabled && (
              <IconButton
                onClick={() => removeTag(option.value)}
                className={s.deleteButton}
                aria-label={`Remove ${option.label}`}
                type="button"
                tabIndex={-1}>
                <DeleteIcon />
              </IconButton>
            )}
          </div>
        ))}

        {/* Search input */}
        <div className={s.inputContainer}>
          <input
            id={id}
            ref={inputRef}
            type="text"
            className={s.input}
            value={searchTerm}
            onChange={handleInputChange}
            onFocus={handleInputFocus}
            onKeyDown={handleKeyDown}
            placeholder={value.length === 0 ? placeholder : ''}
            disabled={disabled || isMaxTagsReached}
            autoComplete="off"
          />
        </div>

        {/* Dropdown arrow */}
        <ArrowDownIcon
          className={clsx(s.dropdownIcon, isOpen && s.dropdownIconOpen)}
          onClick={() => !disabled && setIsOpen(!isOpen)}
        />
      </div>

      {/* Dropdown */}
      {isOpen && !disabled && (
        <div className={s.dropdown}>
          {filteredOptions.length > 0 ? (
            filteredOptions.map((option, index) => (
              <div
                key={option.value}
                className={clsx(
                  s.option,
                  index === focusedIndex && s.optionFocused,
                  option.disabled && s.optionDisabled
                )}
                onClick={() => !option.disabled && selectOption(option)}
                onMouseEnter={() => setFocusedIndex(index)}>
                <Typography variant="body2">{option.label}</Typography>
              </div>
            ))
          ) : (
            <div className={s.noResults}>
              <Typography variant="body2" className={s.noResultsText}>
                {searchTerm ? 'No options found' : 'All options selected'}
              </Typography>
            </div>
          )}
        </div>
      )}

      {/* Error message */}
      {showError && (
        <Typography variant="error" className={s.errorMessage}>
          {errorMessage}
        </Typography>
      )}

      {/* Tags counter */}
      {maxTags && (
        <Typography variant="caption" className={s.counter}>
          {value.length}/{maxTags} selected
        </Typography>
      )}
    </div>
  )
}


================================================
FILE: apps/react-effector-fsd/src/shared/components/Autocomplete/index.ts
================================================
export * from './Autocomplete'


================================================
FILE: apps/react-effector-fsd/src/shared/components/Button/Button.module.css
================================================
.button {
  cursor: pointer;

  display: inline-flex;
  gap: 4px;
  align-items: center;
  justify-content: center;

  height: 40px;
  padding: 8px 16px;
  border-radius: 45px;

  font-size: var(--font-size-s);
  font-weight: 600;
  color: var(--color-text-primary);

  transition: opacity 200ms;
}

.button:focus-visible {
  outline: 2px solid var(--color-outline-focus);
  outline-offset: 2px;
}

.button:disabled {
  cursor: initial;
  background-color: var(--color-disabled);
}

.button:hover:not(:disabled),
.button:focus:not(:disabled) {
  opacity: 0.8;
}

.primary {
  background-color: var(--color-accent);
}

.secondary {
  background-color: var(--color-bg-interactive-secondary);
}

.fullWidth {
  width: 100%;
}


================================================
FILE: apps/react-effector-fsd/src/shared/components/Button/Button.stories.tsx
================================================
import type { Meta, StoryObj } from '@storybook/react-vite'

import { Button } from './Button'

const meta = {
  title: 'Components/Button',
  component: Button,
  parameters: {
    layout: 'centered',
  },
  args: {},
} satisfies Meta<typeof Button>

export default meta
type Story = StoryObj<typeof meta>

export const AllButtons: Story = {
  render: () => (
    <div
      style={{
        display: 'flex',
        gap: '24px',
        flexDirection: 'column',
        alignItems: 'center',
        width: '250px',
      }}>
      <Button variant="primary">Primary</Button>
      <Button variant="secondary">Secondary</Button>
      <Button fullWidth>Full Width</Button>
      <Button disabled>Disabled</Button>
      <Button variant="primary" as="p" href="https://it-incubator.io/" target="_blank">
        Link
      </Button>
    </div>
  ),
}


================================================
FILE: apps/react-effector-fsd/src/shared/components/Button/Button.tsx
================================================
import { clsx } from 'clsx'
import type { ComponentProps, ElementType } from 'react'

import s from './Button.module.css'

export type ButtonVariant = 'primary' | 'secondary'

export type ButtonProps<T extends ElementType = 'button'> = {
  as?: T
  fullWidth?: boolean
  variant?: ButtonVariant
} & ComponentProps<T>

export const Button = <T extends ElementType = 'button'>({
  as: Component = 'button',
  children,
  className,
  fullWidth = false,
  variant = 'primary',
  ...props
}: ButtonProps<T>) => {
  const classNames = clsx(s.button, s[variant], fullWidth && s.fullWidth, className)

  return (
    <Component className={classNames} {...props}>
      {children}
    </Component>
  )
}


================================================
FILE: apps/react-effector-fsd/src/shared/components/Button/index.ts
================================================
export * from './Button'


================================================
FILE: apps/react-effector-fsd/src/shared/components/Card/Card.module.css
================================================
.card {
  display: flex;
  flex-direction: column;
  padding: 8px;
  background: var(--color-bg-card);
}


================================================
FILE: apps/react-effector-fsd/src/shared/components/Card/Card.stories.tsx
================================================
import type { Meta, StoryObj } from '@storybook/react-vite'

import { Typography } from '../Typography'
import { Card } from './Card'

const meta = {
  title: 'Components/Card',
  component: Card,
  parameters: {
    layout: 'centered',
  },
  args: {},
} satisfies Meta<typeof Card>

export default meta

type Story = StoryObj<typeof meta>

export const Basic: Story = {
  render: () => (
    <Card>
      <Typography variant="h2">Chill Mix</Typography>
      <Typography variant="body2" style={{ color: 'var(--color-text-secondary)' }}>
        Julia Wolf, Khalid, ayokay and more
      </Typography>
    </Card>
  ),
}

export const AsSection: Story = {
  render: () => (
    <Card as="section">
      <Typography variant="h3">Card as section</Typography>
      <Typography variant="caption">You can use any tag via 'as' prop</Typography>
    </Card>
  ),
}


================================================
FILE: apps/react-effector-fsd/src/shared/components/Card/Card.tsx
================================================
import { clsx } from 'clsx'
import type { ComponentProps, ElementType, ReactNode } from 'react'

import s from './Card.module.css'

export type CardProps<T extends ElementType = 'div'> = {
  as?: T
  className?: string
  children?: ReactNode
} & ComponentProps<T>

export const Car
Download .txt
gitextract_xkduu9og/

├── .github/
│   └── workflows/
│       ├── ci-rtk.yml
│       ├── ci-tanstack.yml
│       ├── deploy-effector.yml
│       ├── deploy-reatom.yml
│       ├── deploy-root.yml
│       ├── deploy-rtk.yml
│       ├── deploy-tanstack.yml
│       └── deploy.yml
├── .gitignore
├── .husky/
│   ├── pre-commit
│   └── pre-push
├── .prettierignore
├── .prettierrc
├── CONTRIBUTING.md
├── FRONTEND_API_CHANGES.md
├── README.md
├── apps/
│   ├── nextjs/
│   │   ├── .gitignore
│   │   ├── README.md
│   │   ├── eslint.config.mjs
│   │   ├── next.config.ts
│   │   ├── package.json
│   │   ├── src/
│   │   │   ├── app/
│   │   │   │   ├── actions/
│   │   │   │   │   └── auth/
│   │   │   │   │       └── logout.action.tsx
│   │   │   │   ├── api/
│   │   │   │   │   └── oauth/
│   │   │   │   │       └── callback/
│   │   │   │   │           └── route.ts
│   │   │   │   ├── globals.css
│   │   │   │   ├── layout.tsx
│   │   │   │   ├── page.module.css
│   │   │   │   ├── page.tsx
│   │   │   │   ├── profile/
│   │   │   │   │   └── page.tsx
│   │   │   │   └── redirect/
│   │   │   │       └── page.tsx
│   │   │   ├── features/
│   │   │   │   └── auth/
│   │   │   │       └── ui/
│   │   │   │           ├── Login/
│   │   │   │           │   └── Login.tsx
│   │   │   │           ├── Logout/
│   │   │   │           │   └── Logout.tsx
│   │   │   │           ├── MeInfo/
│   │   │   │           │   └── MeInfo.tsx
│   │   │   │           └── UserBlock.tsx
│   │   │   ├── middleware.ts
│   │   │   ├── reauth-middleware.ts
│   │   │   └── shared/
│   │   │       ├── api/
│   │   │       │   ├── auth-api.ts
│   │   │       │   ├── authApi.types.ts
│   │   │       │   ├── base.ts
│   │   │       │   └── tracks/
│   │   │       │       ├── tracksApi.ts
│   │   │       │       └── tracksApi.types.ts
│   │   │       ├── common.types.ts
│   │   │       └── utils/
│   │   │           ├── cookieHelpers.ts
│   │   │           └── jwt-util.ts
│   │   └── tsconfig.json
│   ├── react-effector-fsd/
│   │   ├── .gitignore
│   │   ├── README.md
│   │   ├── eslint.config.js
│   │   ├── index.html
│   │   ├── package.json
│   │   ├── src/
│   │   │   ├── app/
│   │   │   │   ├── App.tsx
│   │   │   │   ├── main.tsx
│   │   │   │   ├── model/
│   │   │   │   │   └── init.ts
│   │   │   │   ├── routes/
│   │   │   │   │   ├── Routing.tsx
│   │   │   │   │   └── index.ts
│   │   │   │   └── styles/
│   │   │   │       ├── fonts.css
│   │   │   │       ├── global.css
│   │   │   │       ├── reset.css
│   │   │   │       └── variables.css
│   │   │   ├── features/
│   │   │   │   └── auth/
│   │   │   │       ├── api/
│   │   │   │       │   ├── login.ts
│   │   │   │       │   ├── logout.ts
│   │   │   │       │   └── me.ts
│   │   │   │       ├── index.ts
│   │   │   │       ├── model/
│   │   │   │       │   ├── auth-api.types.ts
│   │   │   │       │   ├── model.ts
│   │   │   │       │   └── user.types.ts
│   │   │   │       └── ui/
│   │   │   │           ├── LoginButtonAndModal/
│   │   │   │           │   ├── LoginButtonAndModal.module.css
│   │   │   │           │   ├── LoginButtonAndModal.tsx
│   │   │   │           │   └── index.ts
│   │   │   │           ├── ProfileDropdownMenu/
│   │   │   │           │   ├── ProfileDropdownMenu.module.css
│   │   │   │           │   ├── ProfileDropdownMenu.stories.tsx
│   │   │   │           │   ├── ProfileDropdownMenu.tsx
│   │   │   │           │   └── index.ts
│   │   │   │           └── index.ts
│   │   │   ├── pages/
│   │   │   │   ├── auth/
│   │   │   │   │   └── OAuthRedirect/
│   │   │   │   │       ├── OAuthCallback.module.css
│   │   │   │   │       └── OAuthCallback.tsx
│   │   │   │   ├── home/
│   │   │   │   │   ├── Home.tsx
│   │   │   │   │   └── index.ts
│   │   │   │   └── user/
│   │   │   │       ├── UserPage.tsx
│   │   │   │       └── index.ts
│   │   │   ├── shared/
│   │   │   │   ├── api/
│   │   │   │   │   ├── client.ts
│   │   │   │   │   ├── schema.ts
│   │   │   │   │   └── utils/
│   │   │   │   │       ├── json-api-error.ts
│   │   │   │   │       └── request-wrapper.ts
│   │   │   │   ├── components/
│   │   │   │   │   ├── AudioPlayer/
│   │   │   │   │   │   ├── AudioPlayer.module.css
│   │   │   │   │   │   ├── AudioPlayer.stories.tsx
│   │   │   │   │   │   ├── AudioPlayer.tsx
│   │   │   │   │   │   └── index.ts
│   │   │   │   │   ├── Autocomplete/
│   │   │   │   │   │   ├── Autocomplete.module.css
│   │   │   │   │   │   ├── Autocomplete.stories.tsx
│   │   │   │   │   │   ├── Autocomplete.tsx
│   │   │   │   │   │   └── index.ts
│   │   │   │   │   ├── Button/
│   │   │   │   │   │   ├── Button.module.css
│   │   │   │   │   │   ├── Button.stories.tsx
│   │   │   │   │   │   ├── Button.tsx
│   │   │   │   │   │   └── index.ts
│   │   │   │   │   ├── Card/
│   │   │   │   │   │   ├── Card.module.css
│   │   │   │   │   │   ├── Card.stories.tsx
│   │   │   │   │   │   ├── Card.tsx
│   │   │   │   │   │   └── index.ts
│   │   │   │   │   ├── Dialog/
│   │   │   │   │   │   ├── Dialog.module.css
│   │   │   │   │   │   ├── Dialog.stories.tsx
│   │   │   │   │   │   ├── Dialog.tsx
│   │   │   │   │   │   └── index.ts
│   │   │   │   │   ├── DropdownMenu/
│   │   │   │   │   │   ├── DropdownMenu.module.css
│   │   │   │   │   │   ├── DropdownMenu.stories.tsx
│   │   │   │   │   │   ├── DropdownMenu.tsx
│   │   │   │   │   │   └── index.ts
│   │   │   │   │   ├── Hashtag/
│   │   │   │   │   │   ├── Tag.module.css
│   │   │   │   │   │   ├── Tag.stories.tsx
│   │   │   │   │   │   ├── Tag.tsx
│   │   │   │   │   │   └── index.ts
│   │   │   │   │   ├── IconButton/
│   │   │   │   │   │   ├── IconButton.module.css
│   │   │   │   │   │   ├── IconButton.stories.tsx
│   │   │   │   │   │   ├── IconButton.tsx
│   │   │   │   │   │   └── index.ts
│   │   │   │   │   ├── ImageUploader/
│   │   │   │   │   │   ├── ImageUploader.module.css
│   │   │   │   │   │   ├── ImageUploader.stories.tsx
│   │   │   │   │   │   ├── ImageUploader.tsx
│   │   │   │   │   │   └── index.ts
│   │   │   │   │   ├── Pagination/
│   │   │   │   │   │   ├── Pagination.module.css
│   │   │   │   │   │   ├── Pagination.stories.tsx
│   │   │   │   │   │   ├── Pagination.tsx
│   │   │   │   │   │   └── index.ts
│   │   │   │   │   ├── Progress/
│   │   │   │   │   │   ├── Progress.module.css
│   │   │   │   │   │   ├── Progress.stories.tsx
│   │   │   │   │   │   ├── Progress.tsx
│   │   │   │   │   │   └── index.ts
│   │   │   │   │   ├── ReactionButtons/
│   │   │   │   │   │   ├── ReactionButtons.module.css
│   │   │   │   │   │   ├── ReactionButtons.stories.tsx
│   │   │   │   │   │   ├── ReactionButtons.tsx
│   │   │   │   │   │   └── index.ts
│   │   │   │   │   ├── SearchField/
│   │   │   │   │   │   ├── SearchField.module.css
│   │   │   │   │   │   ├── SearchField.stories.tsx
│   │   │   │   │   │   ├── SearchField.tsx
│   │   │   │   │   │   └── index.ts
│   │   │   │   │   ├── Select/
│   │   │   │   │   │   ├── Select.module.css
│   │   │   │   │   │   ├── Select.stories.tsx
│   │   │   │   │   │   ├── Select.tsx
│   │   │   │   │   │   └── index.ts
│   │   │   │   │   ├── SortSelect/
│   │   │   │   │   │   └── Select.tsx
│   │   │   │   │   ├── Table/
│   │   │   │   │   │   ├── Table.module.css
│   │   │   │   │   │   ├── Table.stories.tsx
│   │   │   │   │   │   ├── Table.tsx
│   │   │   │   │   │   └── index.ts
│   │   │   │   │   ├── Tabs/
│   │   │   │   │   │   ├── Tabs.module.css
│   │   │   │   │   │   ├── Tabs.stories.tsx
│   │   │   │   │   │   ├── Tabs.tsx
│   │   │   │   │   │   └── index.ts
│   │   │   │   │   ├── TagEditor/
│   │   │   │   │   │   ├── TagEditor.module.css
│   │   │   │   │   │   ├── TagEditor.stories.tsx
│   │   │   │   │   │   ├── TagEditor.tsx
│   │   │   │   │   │   └── index.ts
│   │   │   │   │   ├── TextField/
│   │   │   │   │   │   ├── TextField.module.css
│   │   │   │   │   │   ├── TextField.stories.tsx
│   │   │   │   │   │   ├── TextField.tsx
│   │   │   │   │   │   └── index.ts
│   │   │   │   │   ├── Textarea/
│   │   │   │   │   │   ├── Textarea.module.css
│   │   │   │   │   │   ├── Textarea.stories.tsx
│   │   │   │   │   │   ├── Textarea.tsx
│   │   │   │   │   │   └── index.ts
│   │   │   │   │   ├── Typography/
│   │   │   │   │   │   ├── Typography.module.css
│   │   │   │   │   │   ├── Typography.stories.tsx
│   │   │   │   │   │   ├── Typography.tsx
│   │   │   │   │   │   └── index.ts
│   │   │   │   │   └── index.ts
│   │   │   │   ├── config/
│   │   │   │   │   └── config.ts
│   │   │   │   ├── hooks/
│   │   │   │   │   ├── index.ts
│   │   │   │   │   ├── useDebounceValue.ts
│   │   │   │   │   └── useGetId.ts
│   │   │   │   └── icons/
│   │   │   │       ├── AddToPlaylistIcon.tsx
│   │   │   │       ├── ArrowDownIcon.tsx
│   │   │   │       ├── ClockIcon.tsx
│   │   │   │       ├── CreateIcon.tsx
│   │   │   │       ├── DeleteIcon.tsx
│   │   │   │       ├── DislikeIcon.tsx
│   │   │   │       ├── DownloadIcon.tsx
│   │   │   │       ├── EditIcon.tsx
│   │   │   │       ├── HomeIcon.tsx
│   │   │   │       ├── ImageUploadIcon.tsx
│   │   │   │       ├── KeyboardArrowLeftIcon.tsx
│   │   │   │       ├── KeyboardArrowRightIcon.tsx
│   │   │   │       ├── LibraryIcon.tsx
│   │   │   │       ├── LikeIcon.tsx
│   │   │   │       ├── LikeIconFill.tsx
│   │   │   │       ├── LikeInSquareIcon.tsx
│   │   │   │       ├── LiveWaveIcon/
│   │   │   │       │   ├── LiveWaveIcon.module.css
│   │   │   │       │   ├── LiveWaveIcon.tsx
│   │   │   │       │   └── index.ts
│   │   │   │       ├── LogoutIcon.tsx
│   │   │   │       ├── MoreIcon.tsx
│   │   │   │       ├── PauseIcon.tsx
│   │   │   │       ├── PlayIcon.tsx
│   │   │   │       ├── PlaylistIcon.tsx
│   │   │   │       ├── PlusIcon.tsx
│   │   │   │       ├── ProfileIcon.tsx
│   │   │   │       ├── RepeatIcon.tsx
│   │   │   │       ├── SearchIcon.tsx
│   │   │   │       ├── ShuffleIcon.tsx
│   │   │   │       ├── SkipNextIcon.tsx
│   │   │   │       ├── SkipPreviousIcon.tsx
│   │   │   │       ├── TextIcon.tsx
│   │   │   │       ├── TrackIcon.tsx
│   │   │   │       ├── UploadIcon.tsx
│   │   │   │       ├── VolumeIcon.tsx
│   │   │   │       ├── VolumeMuteIcon.tsx
│   │   │   │       └── index.ts
│   │   │   └── widgets/
│   │   │       └── layout/
│   │   │           ├── index.ts
│   │   │           └── ui/
│   │   │               ├── Header/
│   │   │               │   ├── Header.module.css
│   │   │               │   └── Header.tsx
│   │   │               ├── Layout.module.css
│   │   │               ├── Layout.tsx
│   │   │               └── Sidebar/
│   │   │                   ├── MenuLinks/
│   │   │                   │   ├── MenuLinks.module.css
│   │   │                   │   └── MenuLinks.tsx
│   │   │                   ├── Sidebar.module.css
│   │   │                   └── Sidebar.tsx
│   │   ├── tsconfig.json
│   │   └── vite.config.ts
│   ├── react-native-expo/
│   │   ├── .gitignore
│   │   ├── .npmrc
│   │   ├── app/
│   │   │   ├── (app)/
│   │   │   │   ├── _layout.tsx
│   │   │   │   ├── index.tsx
│   │   │   │   ├── library/
│   │   │   │   │   └── library.tsx
│   │   │   │   ├── playlists/
│   │   │   │   │   └── playlists.tsx
│   │   │   │   └── tracks/
│   │   │   │       └── tracks.tsx
│   │   │   ├── (auth)/
│   │   │   │   ├── _layout.tsx
│   │   │   │   └── login.tsx
│   │   │   └── _layout.tsx
│   │   ├── app.config.ts
│   │   ├── babel.config.js
│   │   ├── declarations.d.ts
│   │   ├── features/
│   │   │   ├── auth/
│   │   │   │   ├── components/
│   │   │   │   │   ├── LoginButton/
│   │   │   │   │   │   └── LoginButton.tsx
│   │   │   │   │   └── LogoutButton/
│   │   │   │   │       └── LogoutButton.tsx
│   │   │   │   └── model/
│   │   │   │       ├── api/
│   │   │   │       │   ├── auth-instanse/
│   │   │   │       │   │   └── auth-instanse.ts
│   │   │   │       │   └── hooks/
│   │   │   │       │       ├── use-login-mutatuion.ts
│   │   │   │       │       ├── use-logout-mutation.ts
│   │   │   │       │       └── use-me.query.ts
│   │   │   │       ├── config/
│   │   │   │       │   └── oauth.ts
│   │   │   │       ├── context/
│   │   │   │       │   └── AuthContext.tsx
│   │   │   │       ├── types/
│   │   │   │       │   └── api.types.ts
│   │   │   │       └── utils/
│   │   │   │           ├── expoUrlToHttpCallback.ts
│   │   │   │           └── getOauthRedirectUrl.ts
│   │   │   └── playlists/
│   │   │       └── model/
│   │   │           └── api/
│   │   │               └── playlist-instance/
│   │   │                   └── playlist-instance.ts
│   │   ├── index.ts
│   │   ├── metro.config.js
│   │   ├── package.json
│   │   ├── pnpm-lock.yaml.2457664388
│   │   ├── shared/
│   │   │   ├── api/
│   │   │   │   ├── api-root/
│   │   │   │   │   ├── api-root-instanse.ts
│   │   │   │   │   └── api-root.ts
│   │   │   │   ├── query-client/
│   │   │   │   │   └── queryClient.ts
│   │   │   │   └── query-persist/
│   │   │   │       └── query-presist.ts
│   │   │   ├── consts/
│   │   │   │   ├── consts.ts
│   │   │   │   └── key-storage/
│   │   │   │       └── key-storage.ts
│   │   │   ├── providers/
│   │   │   │   └── reactQueryProviders/
│   │   │   │       └── ReactQueryProviders.tsx
│   │   │   ├── storage/
│   │   │   │   └── tokenStorage.ts
│   │   │   ├── styles/
│   │   │   │   ├── tokens.ts
│   │   │   │   └── tokens.type.ts
│   │   │   ├── ui/
│   │   │   │   ├── Button/
│   │   │   │   │   ├── Button.tsx
│   │   │   │   │   └── Button.type.tsx
│   │   │   │   └── Icons/
│   │   │   │       ├── navigation/
│   │   │   │       │   ├── IcAllPlaylist.tsx
│   │   │   │       │   ├── IcAllTracks.tsx
│   │   │   │       │   ├── IcHome.tsx
│   │   │   │       │   └── IcYourLibrary.tsx
│   │   │   │       └── screens/
│   │   │   │           └── login/
│   │   │   │               └── IcSmile.tsx
│   │   │   └── utils/
│   │   │       └── makeFullUrl.ts
│   │   └── tsconfig.json
│   ├── reatom/
│   │   ├── .gitignore
│   │   ├── .storybook/
│   │   │   ├── main.ts
│   │   │   └── preview.tsx
│   │   ├── README.md
│   │   ├── eslint.config.js
│   │   ├── index.html
│   │   ├── package.json
│   │   ├── src/
│   │   │   ├── app/
│   │   │   │   ├── App.tsx
│   │   │   │   ├── entrypoint/
│   │   │   │   │   └── main.tsx
│   │   │   │   ├── query-client/
│   │   │   │   │   └── query-client.tsx
│   │   │   │   ├── routing/
│   │   │   │   │   ├── Routing.tsx
│   │   │   │   │   └── index.ts
│   │   │   │   └── styles/
│   │   │   │       ├── fonts.css
│   │   │   │       ├── global.css
│   │   │   │       ├── reset.css
│   │   │   │       └── variables.css
│   │   │   ├── entities/
│   │   │   │   └── playlist/
│   │   │   │       ├── index.tsx
│   │   │   │       └── ui/
│   │   │   │           ├── PlaylistCard/
│   │   │   │           │   ├── PlaylistCard.module.css
│   │   │   │           │   ├── PlaylistCard.stories.tsx
│   │   │   │           │   ├── PlaylistCard.tsx
│   │   │   │           │   └── index.ts
│   │   │   │           └── PlaylistItem/
│   │   │   │               ├── PlaylistItem.tsx
│   │   │   │               ├── PlaylistItem.types.ts
│   │   │   │               └── index.ts
│   │   │   ├── features/
│   │   │   │   ├── artists/
│   │   │   │   │   ├── api/
│   │   │   │   │   │   ├── artists-api.ts
│   │   │   │   │   │   └── index.ts
│   │   │   │   │   ├── index.ts
│   │   │   │   │   └── ui/
│   │   │   │   │       └── ArtistCard/
│   │   │   │   │           ├── ArtistCard.module.css
│   │   │   │   │           ├── ArtistCard.stories.tsx
│   │   │   │   │           ├── ArtistCard.tsx
│   │   │   │   │           └── index.ts
│   │   │   │   ├── auth/
│   │   │   │   │   ├── api/
│   │   │   │   │   │   ├── use-login.mutation.ts
│   │   │   │   │   │   ├── use-logout.mutation.ts
│   │   │   │   │   │   └── use-me.query.ts
│   │   │   │   │   ├── index.ts
│   │   │   │   │   ├── types/
│   │   │   │   │   │   └── auth-api.types.ts
│   │   │   │   │   └── ui/
│   │   │   │   │       ├── LoginButtonAndModal/
│   │   │   │   │       │   ├── LoginButtonAndModal.module.css
│   │   │   │   │       │   ├── LoginButtonAndModal.tsx
│   │   │   │   │       │   └── index.ts
│   │   │   │   │       ├── ProfileDropdownMenu/
│   │   │   │   │       │   ├── ProfileDropdownMenu.module.css
│   │   │   │   │       │   ├── ProfileDropdownMenu.stories.tsx
│   │   │   │   │       │   ├── ProfileDropdownMenu.tsx
│   │   │   │   │       │   └── index.ts
│   │   │   │   │       └── index.ts
│   │   │   │   ├── playlists/
│   │   │   │   │   ├── api/
│   │   │   │   │   │   ├── index.ts
│   │   │   │   │   │   ├── playlistsApi.ts
│   │   │   │   │   │   ├── query-key-factory.ts
│   │   │   │   │   │   ├── types.ts
│   │   │   │   │   │   └── use-playlists.query.ts
│   │   │   │   │   ├── index.ts
│   │   │   │   │   ├── model/
│   │   │   │   │   │   └── model.tsx
│   │   │   │   │   └── ui/
│   │   │   │   │       ├── CreatePlaylistModal/
│   │   │   │   │       │   ├── CreatePlaylistModal.module.css
│   │   │   │   │       │   ├── CreatePlaylistModal.tsx
│   │   │   │   │       │   └── index.ts
│   │   │   │   │       ├── PlaylistOverview/
│   │   │   │   │       │   ├── PlaylistOverview.module.css
│   │   │   │   │       │   ├── PlaylistOverview.stories.tsx
│   │   │   │   │       │   ├── PlaylistOverview.tsx
│   │   │   │   │       │   └── index.ts
│   │   │   │   │       └── index.ts
│   │   │   │   ├── reactions/
│   │   │   │   │   ├── index.ts
│   │   │   │   │   └── ui/
│   │   │   │   │       ├── ReactionProvider/
│   │   │   │   │       │   ├── ReactionProvider.tsx
│   │   │   │   │       │   └── index.ts
│   │   │   │   │       └── index.ts
│   │   │   │   ├── tags/
│   │   │   │   │   ├── api/
│   │   │   │   │   │   ├── index.ts
│   │   │   │   │   │   ├── tags-api.ts
│   │   │   │   │   │   └── use-tags.query.ts
│   │   │   │   │   ├── index.ts
│   │   │   │   │   └── ui/
│   │   │   │   │       ├── TagsList/
│   │   │   │   │       │   ├── TagsList.module.css
│   │   │   │   │       │   ├── TagsList.stories.tsx
│   │   │   │   │       │   ├── TagsList.tsx
│   │   │   │   │       │   └── index.ts
│   │   │   │   │       └── index.ts
│   │   │   │   └── tracks/
│   │   │   │       ├── api/
│   │   │   │       │   ├── index.ts
│   │   │   │       │   ├── tracksApi.ts
│   │   │   │       │   └── types.ts
│   │   │   │       ├── index.ts
│   │   │   │       └── ui/
│   │   │   │           ├── TrackCard/
│   │   │   │           │   ├── TrackCard.module.css
│   │   │   │           │   ├── TrackCard.stories.tsx
│   │   │   │           │   ├── TrackCard.tsx
│   │   │   │           │   └── index.ts
│   │   │   │           ├── TrackInfoCell/
│   │   │   │           │   ├── TrackInfoCell.module.css
│   │   │   │           │   ├── TrackInfoCell.tsx
│   │   │   │           │   └── index.ts
│   │   │   │           ├── TrackOverview/
│   │   │   │           │   ├── TrackOverview.module.css
│   │   │   │           │   ├── TrackOverview.stories.tsx
│   │   │   │           │   ├── TrackOverview.tsx
│   │   │   │           │   └── index.ts
│   │   │   │           ├── TrackRow/
│   │   │   │           │   ├── TrackRow.module.css
│   │   │   │           │   └── TrackRow.tsx
│   │   │   │           ├── TracksTable/
│   │   │   │           │   ├── TrackTable.stories.tsx
│   │   │   │           │   ├── TracksTable.tsx
│   │   │   │           │   └── index.ts
│   │   │   │           └── index.ts
│   │   │   ├── layout/
│   │   │   │   ├── Header/
│   │   │   │   │   ├── Header.module.css
│   │   │   │   │   ├── Header.tsx
│   │   │   │   │   └── index.ts
│   │   │   │   ├── Layout.module.css
│   │   │   │   ├── Layout.tsx
│   │   │   │   ├── Sidebar/
│   │   │   │   │   ├── MenuLinks/
│   │   │   │   │   │   ├── MenuLinks.module.css
│   │   │   │   │   │   ├── MenuLinks.tsx
│   │   │   │   │   │   └── index.ts
│   │   │   │   │   ├── Sidebar.module.css
│   │   │   │   │   ├── Sidebar.tsx
│   │   │   │   │   └── index.ts
│   │   │   │   └── index.ts
│   │   │   ├── pages/
│   │   │   │   ├── MainPage/
│   │   │   │   │   ├── MainPage.module.css
│   │   │   │   │   ├── MainPage.tsx
│   │   │   │   │   └── index.ts
│   │   │   │   ├── PlaylistPage/
│   │   │   │   │   ├── PlaylistPage.module.css
│   │   │   │   │   ├── PlaylistPage.tsx
│   │   │   │   │   ├── index.ts
│   │   │   │   │   └── ui/
│   │   │   │   │       └── ControlPanel/
│   │   │   │   │           ├── ControlPanel.module.css
│   │   │   │   │           ├── ControlPanel.tsx
│   │   │   │   │           └── index.ts
│   │   │   │   ├── PlaylistsPage/
│   │   │   │   │   ├── PlaylistsPage.module.css
│   │   │   │   │   ├── PlaylistsPage.tsx
│   │   │   │   │   ├── PlaylistsPage.types.ts
│   │   │   │   │   └── index.ts
│   │   │   │   ├── TrackPage/
│   │   │   │   │   ├── TrackPage.module.css
│   │   │   │   │   ├── TrackPage.tsx
│   │   │   │   │   ├── index.ts
│   │   │   │   │   └── ui/
│   │   │   │   │       └── ControlPanel/
│   │   │   │   │           ├── ControlPanel.module.css
│   │   │   │   │           ├── ControlPanel.tsx
│   │   │   │   │           └── index.ts
│   │   │   │   ├── TracksPage/
│   │   │   │   │   ├── TracksPage.module.css
│   │   │   │   │   ├── TracksPage.tsx
│   │   │   │   │   └── index.ts
│   │   │   │   ├── UserPage/
│   │   │   │   │   ├── UserPage.module.css
│   │   │   │   │   ├── UserPage.tsx
│   │   │   │   │   ├── index.ts
│   │   │   │   │   └── ui/
│   │   │   │   │       ├── UserInfo/
│   │   │   │   │       │   ├── UserInfo.module.css
│   │   │   │   │       │   ├── UserInfo.tsx
│   │   │   │   │       │   └── index.ts
│   │   │   │   │       ├── UserTabs/
│   │   │   │   │       │   ├── LikedTracksTab/
│   │   │   │   │       │   │   ├── LikedTracksTab.module.css
│   │   │   │   │       │   │   ├── LikedTracksTab.tsx
│   │   │   │   │       │   │   └── index.ts
│   │   │   │   │       │   ├── MyLikedPlaylistsTab/
│   │   │   │   │       │   │   ├── MyLikedPlaylistsTab.tsx
│   │   │   │   │       │   │   └── index.ts
│   │   │   │   │       │   ├── PlaylistsTab/
│   │   │   │   │       │   │   ├── PlaylistsTab.module.css
│   │   │   │   │       │   │   ├── PlaylistsTab.tsx
│   │   │   │   │       │   │   └── index.ts
│   │   │   │   │       │   ├── TracksTab/
│   │   │   │   │       │   │   ├── TracksTab.module.css
│   │   │   │   │       │   │   ├── TracksTab.tsx
│   │   │   │   │       │   │   └── index.ts
│   │   │   │   │       │   ├── UserTabs.tsx
│   │   │   │   │       │   └── index.ts
│   │   │   │   │       └── index.ts
│   │   │   │   ├── auth/
│   │   │   │   │   └── OAuthRedirect/
│   │   │   │   │       ├── OAuthCallback.module.css
│   │   │   │   │       └── OAuthCallback.tsx
│   │   │   │   ├── common/
│   │   │   │   │   ├── ContentList/
│   │   │   │   │   │   ├── ContentList.module.css
│   │   │   │   │   │   ├── ContentList.tsx
│   │   │   │   │   │   └── index.ts
│   │   │   │   │   ├── PageWrapper/
│   │   │   │   │   │   ├── PageWrapper.module.css
│   │   │   │   │   │   ├── PageWrapper.tsx
│   │   │   │   │   │   └── index.ts
│   │   │   │   │   ├── SearchTextField/
│   │   │   │   │   │   ├── SearchTextField.tsx
│   │   │   │   │   │   └── index.ts
│   │   │   │   │   ├── SortSelect/
│   │   │   │   │   │   ├── SortSelect.module.css
│   │   │   │   │   │   ├── SortSelect.tsx
│   │   │   │   │   │   └── index.ts
│   │   │   │   │   └── index.ts
│   │   │   │   └── index.ts
│   │   │   ├── shared/
│   │   │   │   ├── api/
│   │   │   │   │   ├── client.ts
│   │   │   │   │   ├── schema.ts
│   │   │   │   │   ├── types.ts
│   │   │   │   │   └── utils/
│   │   │   │   │       ├── json-api-error.ts
│   │   │   │   │       └── request-wrapper.ts
│   │   │   │   ├── components/
│   │   │   │   │   ├── AudioPlayer/
│   │   │   │   │   │   ├── AudioPlayer.module.css
│   │   │   │   │   │   ├── AudioPlayer.stories.tsx
│   │   │   │   │   │   ├── AudioPlayer.tsx
│   │   │   │   │   │   └── index.ts
│   │   │   │   │   ├── Autocomplete/
│   │   │   │   │   │   ├── Autocomplete.module.css
│   │   │   │   │   │   ├── Autocomplete.stories.tsx
│   │   │   │   │   │   ├── Autocomplete.tsx
│   │   │   │   │   │   └── index.ts
│   │   │   │   │   ├── Button/
│   │   │   │   │   │   ├── Button.module.css
│   │   │   │   │   │   ├── Button.stories.tsx
│   │   │   │   │   │   ├── Button.tsx
│   │   │   │   │   │   └── index.ts
│   │   │   │   │   ├── Card/
│   │   │   │   │   │   ├── Card.module.css
│   │   │   │   │   │   ├── Card.stories.tsx
│   │   │   │   │   │   ├── Card.tsx
│   │   │   │   │   │   └── index.ts
│   │   │   │   │   ├── Dialog/
│   │   │   │   │   │   ├── Dialog.module.css
│   │   │   │   │   │   ├── Dialog.stories.tsx
│   │   │   │   │   │   ├── Dialog.tsx
│   │   │   │   │   │   └── index.ts
│   │   │   │   │   ├── DropdownMenu/
│   │   │   │   │   │   ├── DropdownMenu.module.css
│   │   │   │   │   │   ├── DropdownMenu.stories.tsx
│   │   │   │   │   │   ├── DropdownMenu.tsx
│   │   │   │   │   │   └── index.ts
│   │   │   │   │   ├── Hashtag/
│   │   │   │   │   │   ├── Tag.module.css
│   │   │   │   │   │   ├── Tag.stories.tsx
│   │   │   │   │   │   ├── Tag.tsx
│   │   │   │   │   │   └── index.ts
│   │   │   │   │   ├── IconButton/
│   │   │   │   │   │   ├── IconButton.module.css
│   │   │   │   │   │   ├── IconButton.stories.tsx
│   │   │   │   │   │   ├── IconButton.tsx
│   │   │   │   │   │   └── index.ts
│   │   │   │   │   ├── ImageUploader/
│   │   │   │   │   │   ├── ImageUploader.module.css
│   │   │   │   │   │   ├── ImageUploader.stories.tsx
│   │   │   │   │   │   ├── ImageUploader.tsx
│   │   │   │   │   │   └── index.ts
│   │   │   │   │   ├── Pagination/
│   │   │   │   │   │   ├── Pagination.module.css
│   │   │   │   │   │   ├── Pagination.stories.tsx
│   │   │   │   │   │   ├── Pagination.tsx
│   │   │   │   │   │   └── index.ts
│   │   │   │   │   ├── Progress/
│   │   │   │   │   │   ├── Progress.module.css
│   │   │   │   │   │   ├── Progress.stories.tsx
│   │   │   │   │   │   ├── Progress.tsx
│   │   │   │   │   │   └── index.ts
│   │   │   │   │   ├── ReactionButtons/
│   │   │   │   │   │   ├── ReactionButtons.module.css
│   │   │   │   │   │   ├── ReactionButtons.stories.tsx
│   │   │   │   │   │   ├── ReactionButtons.tsx
│   │   │   │   │   │   └── index.ts
│   │   │   │   │   ├── SearchField/
│   │   │   │   │   │   ├── SearchField.module.css
│   │   │   │   │   │   ├── SearchField.stories.tsx
│   │   │   │   │   │   ├── SearchField.tsx
│   │   │   │   │   │   └── index.ts
│   │   │   │   │   ├── Select/
│   │   │   │   │   │   ├── Select.module.css
│   │   │   │   │   │   ├── Select.stories.tsx
│   │   │   │   │   │   ├── Select.tsx
│   │   │   │   │   │   └── index.ts
│   │   │   │   │   ├── SortSelect/
│   │   │   │   │   │   └── Select.tsx
│   │   │   │   │   ├── Table/
│   │   │   │   │   │   ├── Table.module.css
│   │   │   │   │   │   ├── Table.stories.tsx
│   │   │   │   │   │   ├── Table.tsx
│   │   │   │   │   │   └── index.ts
│   │   │   │   │   ├── Tabs/
│   │   │   │   │   │   ├── Tabs.module.css
│   │   │   │   │   │   ├── Tabs.stories.tsx
│   │   │   │   │   │   ├── Tabs.tsx
│   │   │   │   │   │   └── index.ts
│   │   │   │   │   ├── TagEditor/
│   │   │   │   │   │   ├── TagEditor.module.css
│   │   │   │   │   │   ├── TagEditor.stories.tsx
│   │   │   │   │   │   ├── TagEditor.tsx
│   │   │   │   │   │   └── index.ts
│   │   │   │   │   ├── TextField/
│   │   │   │   │   │   ├── TextField.module.css
│   │   │   │   │   │   ├── TextField.stories.tsx
│   │   │   │   │   │   ├── TextField.tsx
│   │   │   │   │   │   └── index.ts
│   │   │   │   │   ├── Textarea/
│   │   │   │   │   │   ├── Textarea.module.css
│   │   │   │   │   │   ├── Textarea.stories.tsx
│   │   │   │   │   │   ├── Textarea.tsx
│   │   │   │   │   │   └── index.ts
│   │   │   │   │   ├── Typography/
│   │   │   │   │   │   ├── Typography.module.css
│   │   │   │   │   │   ├── Typography.stories.tsx
│   │   │   │   │   │   ├── Typography.tsx
│   │   │   │   │   │   └── index.ts
│   │   │   │   │   └── index.ts
│   │   │   │   ├── config/
│   │   │   │   │   └── config.ts
│   │   │   │   ├── hooks/
│   │   │   │   │   ├── index.ts
│   │   │   │   │   ├── useDebounceValue.ts
│   │   │   │   │   └── useGetId.ts
│   │   │   │   ├── icons/
│   │   │   │   │   ├── AddToPlaylistIcon.tsx
│   │   │   │   │   ├── ArrowDownIcon.tsx
│   │   │   │   │   ├── ClockIcon.tsx
│   │   │   │   │   ├── CreateIcon.tsx
│   │   │   │   │   ├── DeleteIcon.tsx
│   │   │   │   │   ├── DislikeIcon.tsx
│   │   │   │   │   ├── DownloadIcon.tsx
│   │   │   │   │   ├── EditIcon.tsx
│   │   │   │   │   ├── HomeIcon.tsx
│   │   │   │   │   ├── ImageUploadIcon.tsx
│   │   │   │   │   ├── KeyboardArrowLeftIcon.tsx
│   │   │   │   │   ├── KeyboardArrowRightIcon.tsx
│   │   │   │   │   ├── LibraryIcon.tsx
│   │   │   │   │   ├── LikeIcon.tsx
│   │   │   │   │   ├── LikeIconFill.tsx
│   │   │   │   │   ├── LikeInSquareIcon.tsx
│   │   │   │   │   ├── LiveWaveIcon/
│   │   │   │   │   │   ├── LiveWaveIcon.module.css
│   │   │   │   │   │   ├── LiveWaveIcon.tsx
│   │   │   │   │   │   └── index.ts
│   │   │   │   │   ├── LogoutIcon.tsx
│   │   │   │   │   ├── MoreIcon.tsx
│   │   │   │   │   ├── PauseIcon.tsx
│   │   │   │   │   ├── PlayIcon.tsx
│   │   │   │   │   ├── PlaylistIcon.tsx
│   │   │   │   │   ├── PlusIcon.tsx
│   │   │   │   │   ├── ProfileIcon.tsx
│   │   │   │   │   ├── RepeatIcon.tsx
│   │   │   │   │   ├── SearchIcon.tsx
│   │   │   │   │   ├── ShuffleIcon.tsx
│   │   │   │   │   ├── SkipNextIcon.tsx
│   │   │   │   │   ├── SkipPreviousIcon.tsx
│   │   │   │   │   ├── TextIcon.tsx
│   │   │   │   │   ├── TrackIcon.tsx
│   │   │   │   │   ├── UploadIcon.tsx
│   │   │   │   │   ├── VolumeIcon.tsx
│   │   │   │   │   ├── VolumeMuteIcon.tsx
│   │   │   │   │   └── index.ts
│   │   │   │   ├── ui/
│   │   │   │   │   ├── prerender-ready.tsx
│   │   │   │   │   └── utils/
│   │   │   │   │       └── query-error-handler-for-rhf-factory.ts
│   │   │   │   └── utils/
│   │   │   │       ├── index.ts
│   │   │   │       └── validators/
│   │   │   │           ├── getType.ts
│   │   │   │           ├── inNun.ts
│   │   │   │           ├── index.ts
│   │   │   │           ├── isArray.ts
│   │   │   │           ├── isFunction.ts
│   │   │   │           ├── isNull.ts
│   │   │   │           ├── isObject.ts
│   │   │   │           ├── isUndefined.ts
│   │   │   │           ├── isValid.ts
│   │   │   │           └── isValidArray.ts
│   │   │   ├── vite-env.d.ts
│   │   │   └── widgets/
│   │   │       └── Player/
│   │   │           ├── Player.module.css
│   │   │           ├── Player.tsx
│   │   │           └── index.ts
│   │   ├── stylelint.config.js
│   │   ├── tsconfig.app.json
│   │   ├── tsconfig.json
│   │   ├── tsconfig.node.json
│   │   └── vite.config.ts
│   ├── rtk-query/
│   │   ├── .gitignore
│   │   ├── .storybook/
│   │   │   ├── main.ts
│   │   │   └── preview.tsx
│   │   ├── CLAUDE.md
│   │   ├── README.md
│   │   ├── eslint.config.js
│   │   ├── index.html
│   │   ├── package.json
│   │   ├── src/
│   │   │   ├── app/
│   │   │   │   ├── App.tsx
│   │   │   │   ├── api/
│   │   │   │   │   ├── base-api.ts
│   │   │   │   │   ├── base-query-with-refresh-token-flow-api.ts
│   │   │   │   │   ├── handleError.ts
│   │   │   │   │   └── index.ts
│   │   │   │   ├── routing/
│   │   │   │   │   ├── Routing.tsx
│   │   │   │   │   └── index.ts
│   │   │   │   └── store/
│   │   │   │       ├── index.ts
│   │   │   │       └── store.ts
│   │   │   ├── features/
│   │   │   │   ├── artists/
│   │   │   │   │   ├── api/
│   │   │   │   │   │   ├── artists-api.ts
│   │   │   │   │   │   └── index.ts
│   │   │   │   │   ├── index.ts
│   │   │   │   │   └── ui/
│   │   │   │   │       ├── ArtistCard/
│   │   │   │   │       │   ├── ArtistCard.module.css
│   │   │   │   │       │   ├── ArtistCard.stories.tsx
│   │   │   │   │       │   ├── ArtistCard.tsx
│   │   │   │   │       │   └── index.ts
│   │   │   │   │       ├── ArtistsTagAutocomplete/
│   │   │   │   │       │   ├── ArtistsTagAutocomplete.module.css
│   │   │   │   │       │   ├── ArtistsTagAutocomplete.tsx
│   │   │   │   │       │   └── index.ts
│   │   │   │   │       └── index.ts
│   │   │   │   ├── auth/
│   │   │   │   │   ├── api/
│   │   │   │   │   │   ├── auth-api.ts
│   │   │   │   │   │   ├── auth-api.types.ts
│   │   │   │   │   │   └── index.ts
│   │   │   │   │   ├── index.ts
│   │   │   │   │   ├── model/
│   │   │   │   │   │   ├── auth-slice.ts
│   │   │   │   │   │   └── index.ts
│   │   │   │   │   └── ui/
│   │   │   │   │       ├── LoginModal/
│   │   │   │   │       │   ├── LoginModal.module.css
│   │   │   │   │       │   ├── LoginModal.tsx
│   │   │   │   │       │   └── index.ts
│   │   │   │   │       ├── OAuthRedirect/
│   │   │   │   │       │   ├── OAuthCallback.module.css
│   │   │   │   │       │   ├── OAuthCallback.tsx
│   │   │   │   │       │   └── index.ts
│   │   │   │   │       └── index.ts
│   │   │   │   ├── playlists/
│   │   │   │   │   ├── api/
│   │   │   │   │   │   ├── index.ts
│   │   │   │   │   │   ├── mocks.ts
│   │   │   │   │   │   ├── playlistsApi.ts
│   │   │   │   │   │   └── playlistsApi.types.ts
│   │   │   │   │   ├── index.ts
│   │   │   │   │   ├── model/
│   │   │   │   │   │   ├── hooks/
│   │   │   │   │   │   │   ├── index.ts
│   │   │   │   │   │   │   ├── useCreatePlaylistModal.ts
│   │   │   │   │   │   │   └── useEditPlaylistModal.ts
│   │   │   │   │   │   ├── index.ts
│   │   │   │   │   │   └── playlists-slice.ts
│   │   │   │   │   └── ui/
│   │   │   │   │       ├── ChoosePlaylistButtonAndModal/
│   │   │   │   │       │   ├── ChoosePlaylistButtonAndModal.module.css
│   │   │   │   │       │   ├── ChoosePlaylistButtonAndModal.tsx
│   │   │   │   │       │   └── index.ts
│   │   │   │   │       ├── ChoosePlaylistModal/
│   │   │   │   │       │   ├── ChoosePlaylistModal.module.css
│   │   │   │   │       │   ├── ChoosePlaylistModal.tsx
│   │   │   │   │       │   └── index.ts
│   │   │   │   │       ├── CreateEditPlaylistModal/
│   │   │   │   │       │   ├── CreateEditPlaylistModal.module.css
│   │   │   │   │       │   ├── CreateEditPlaylistModal.tsx
│   │   │   │   │       │   └── index.ts
│   │   │   │   │       ├── PlaylistActions/
│   │   │   │   │       │   ├── PlaylistActions.tsx
│   │   │   │   │       │   └── index.ts
│   │   │   │   │       ├── PlaylistCard/
│   │   │   │   │       │   ├── PlaylistCard.module.css
│   │   │   │   │       │   ├── PlaylistCard.stories.tsx
│   │   │   │   │       │   ├── PlaylistCard.tsx
│   │   │   │   │       │   └── index.ts
│   │   │   │   │       ├── PlaylistCardSkeleton/
│   │   │   │   │       │   ├── PlaylistCardSkeleton.stories.tsx
│   │   │   │   │       │   ├── PlaylistCardSkeleton.tsx
│   │   │   │   │       │   └── index.ts
│   │   │   │   │       ├── PlaylistOverview/
│   │   │   │   │       │   ├── PlaylistOverview.module.css
│   │   │   │   │       │   ├── PlaylistOverview.stories.tsx
│   │   │   │   │       │   ├── PlaylistOverview.tsx
│   │   │   │   │       │   └── index.ts
│   │   │   │   │       ├── PlaylistRow/
│   │   │   │   │       │   ├── PlaylistRow.module.css
│   │   │   │   │       │   └── PlaylistRow.tsx
│   │   │   │   │       └── index.ts
│   │   │   │   ├── profile/
│   │   │   │   │   ├── config/
│   │   │   │   │   │   ├── empty-profile.ts
│   │   │   │   │   │   └── index.ts
│   │   │   │   │   ├── index.ts
│   │   │   │   │   ├── model/
│   │   │   │   │   │   ├── hook/
│   │   │   │   │   │   │   ├── index.ts
│   │   │   │   │   │   │   ├── useEditProfileModal.ts
│   │   │   │   │   │   │   └── useEditProfileSchema.ts
│   │   │   │   │   │   ├── index.ts
│   │   │   │   │   │   ├── profile-schemas.ts
│   │   │   │   │   │   └── profile-slice.ts
│   │   │   │   │   ├── types/
│   │   │   │   │   │   ├── index.ts
│   │   │   │   │   │   └── profile.type.ts
│   │   │   │   │   ├── ui/
│   │   │   │   │   │   ├── EditProfileModal/
│   │   │   │   │   │   │   ├── EditProfileModal.module.css
│   │   │   │   │   │   │   ├── EditProfileModal.tsx
│   │   │   │   │   │   │   └── index.ts
│   │   │   │   │   │   └── index.ts
│   │   │   │   │   └── utils/
│   │   │   │   │       ├── index.ts
│   │   │   │   │       └── storage-key.ts
│   │   │   │   ├── tags/
│   │   │   │   │   ├── api/
│   │   │   │   │   │   ├── index.ts
│   │   │   │   │   │   ├── tagsApi.ts
│   │   │   │   │   │   └── tagsApi.types.ts
│   │   │   │   │   ├── index.ts
│   │   │   │   │   └── ui/
│   │   │   │   │       ├── PlaylistTagAutocomplete/
│   │   │   │   │       │   ├── PlaylistTagAutocomplete.module.css
│   │   │   │   │       │   ├── PlaylistTagAutocomplete.tsx
│   │   │   │   │       │   └── index.ts
│   │   │   │   │       ├── TagsList/
│   │   │   │   │       │   ├── TagsList.module.css
│   │   │   │   │       │   ├── TagsList.stories.tsx
│   │   │   │   │       │   ├── TagsList.tsx
│   │   │   │   │       │   └── index.ts
│   │   │   │   │       └── index.ts
│   │   │   │   └── tracks/
│   │   │   │       ├── api/
│   │   │   │       │   ├── index.ts
│   │   │   │       │   ├── mocks.ts
│   │   │   │       │   ├── tracksApi.ts
│   │   │   │       │   └── tracksApi.types.ts
│   │   │   │       ├── constants/
│   │   │   │       │   └── index.ts
│   │   │   │       ├── index.ts
│   │   │   │       ├── model/
│   │   │   │       │   ├── hooks/
│   │   │   │       │   │   ├── index.ts
│   │   │   │       │   │   ├── useCreateTrackModal.ts
│   │   │   │       │   │   └── useEditTrackModal.ts
│   │   │   │       │   ├── index.ts
│   │   │   │       │   └── tracks-slice.ts
│   │   │   │       ├── ui/
│   │   │   │       │   ├── CreateEditTrackModal/
│   │   │   │       │   │   ├── CreateEditTrackModal.module.css
│   │   │   │       │   │   ├── CreateEditTrackModal.tsx
│   │   │   │       │   │   └── index.ts
│   │   │   │       │   ├── TrackActions/
│   │   │   │       │   │   ├── TrackActions.tsx
│   │   │   │       │   │   ├── TrackActionsMenu/
│   │   │   │       │   │   │   ├── TrackActionsMenu.tsx
│   │   │   │       │   │   │   └── index.ts
│   │   │   │       │   │   └── index.ts
│   │   │   │       │   ├── TrackCard/
│   │   │   │       │   │   ├── TrackCard.module.css
│   │   │   │       │   │   ├── TrackCard.stories.tsx
│   │   │   │       │   │   ├── TrackCard.tsx
│   │   │   │       │   │   └── index.ts
│   │   │   │       │   ├── TrackInfoCell/
│   │   │   │       │   │   ├── TrackInfoCell.module.css
│   │   │   │       │   │   ├── TrackInfoCell.tsx
│   │   │   │       │   │   └── index.ts
│   │   │   │       │   ├── TrackOverview/
│   │   │   │       │   │   ├── TrackOverview.module.css
│   │   │   │       │   │   ├── TrackOverview.stories.tsx
│   │   │   │       │   │   ├── TrackOverview.tsx
│   │   │   │       │   │   └── index.ts
│   │   │   │       │   ├── TrackRow/
│   │   │   │       │   │   ├── TrackRow.module.css
│   │   │   │       │   │   └── TrackRow.tsx
│   │   │   │       │   ├── TrackRowContainer/
│   │   │   │       │   │   ├── TrackRowContainer.tsx
│   │   │   │       │   │   └── index.ts
│   │   │   │       │   ├── TracksTable/
│   │   │   │       │   │   ├── TrackTable.stories.tsx
│   │   │   │       │   │   ├── TracksTable.tsx
│   │   │   │       │   │   └── index.ts
│   │   │   │       │   ├── TracksTableSkeleton/
│   │   │   │       │   │   ├── TracksTableSkeleton.tsx
│   │   │   │       │   │   └── index.ts
│   │   │   │       │   └── index.ts
│   │   │   │       └── utils/
│   │   │   │           └── playlistSync.ts
│   │   │   ├── layout/
│   │   │   │   ├── AppLoader/
│   │   │   │   │   ├── AppLoader.tsx
│   │   │   │   │   └── index.ts
│   │   │   │   ├── Header/
│   │   │   │   │   ├── AccountMenu/
│   │   │   │   │   │   ├── AccountMenu.module.css
│   │   │   │   │   │   ├── AccountMenu.stories.tsx
│   │   │   │   │   │   ├── AccountMenu.tsx
│   │   │   │   │   │   └── index.ts
│   │   │   │   │   ├── Header.module.css
│   │   │   │   │   ├── Header.tsx
│   │   │   │   │   └── index.ts
│   │   │   │   ├── Layout.module.css
│   │   │   │   ├── Layout.tsx
│   │   │   │   ├── Sidebar/
│   │   │   │   │   ├── MenuLinks/
│   │   │   │   │   │   ├── MenuLinks.module.css
│   │   │   │   │   │   ├── MenuLinks.tsx
│   │   │   │   │   │   └── index.ts
│   │   │   │   │   ├── Sidebar.module.css
│   │   │   │   │   ├── Sidebar.tsx
│   │   │   │   │   └── index.ts
│   │   │   │   └── index.ts
│   │   │   ├── main.tsx
│   │   │   ├── pages/
│   │   │   │   ├── MainPage/
│   │   │   │   │   ├── MainPage.module.css
│   │   │   │   │   ├── MainPage.tsx
│   │   │   │   │   └── index.ts
│   │   │   │   ├── PlaylistPage/
│   │   │   │   │   ├── PlaylistPage.module.css
│   │   │   │   │   ├── PlaylistPage.tsx
│   │   │   │   │   ├── index.ts
│   │   │   │   │   └── ui/
│   │   │   │   │       ├── ControlPanel/
│   │   │   │   │       │   ├── ControlPanel.module.css
│   │   │   │   │       │   ├── ControlPanel.tsx
│   │   │   │   │       │   └── index.ts
│   │   │   │   │       └── PlaylistPageSkeleton/
│   │   │   │   │           ├── PlaylistPageSkeleton.module.css
│   │   │   │   │           ├── PlaylistPageSkeleton.tsx
│   │   │   │   │           └── index.ts
│   │   │   │   ├── PlaylistsPage/
│   │   │   │   │   ├── PlaylistsPage.module.css
│   │   │   │   │   ├── PlaylistsPage.tsx
│   │   │   │   │   └── index.ts
│   │   │   │   ├── TrackLyricsPage/
│   │   │   │   │   ├── TrackLyricsPage.module.css
│   │   │   │   │   ├── TrackLyricsPage.tsx
│   │   │   │   │   └── index.ts
│   │   │   │   ├── TrackPage/
│   │   │   │   │   ├── TrackPage.module.css
│   │   │   │   │   ├── TrackPage.tsx
│   │   │   │   │   ├── index.ts
│   │   │   │   │   └── ui/
│   │   │   │   │       ├── ControlPanel/
│   │   │   │   │       │   ├── ControlPanel.module.css
│   │   │   │   │       │   ├── ControlPanel.tsx
│   │   │   │   │       │   └── index.ts
│   │   │   │   │       └── TrackPageSkeleton/
│   │   │   │   │           ├── TrackPageSkeleton.module.css
│   │   │   │   │           ├── TrackPageSkeleton.tsx
│   │   │   │   │           └── index.ts
│   │   │   │   ├── TracksPage/
│   │   │   │   │   ├── TracksPage.module.css
│   │   │   │   │   ├── TracksPage.tsx
│   │   │   │   │   └── index.ts
│   │   │   │   ├── UserPage/
│   │   │   │   │   ├── UserPage.module.css
│   │   │   │   │   ├── UserPage.tsx
│   │   │   │   │   ├── hooks/
│   │   │   │   │   │   ├── index.ts
│   │   │   │   │   │   ├── useOwnerData.ts
│   │   │   │   │   │   └── useUserPageBackgroundColor.ts
│   │   │   │   │   ├── index.ts
│   │   │   │   │   └── ui/
│   │   │   │   │       ├── UserInfo/
│   │   │   │   │       │   ├── UserInfo.module.css
│   │   │   │   │       │   ├── UserInfo.tsx
│   │   │   │   │       │   ├── UserInfoSkeleton/
│   │   │   │   │       │   │   ├── UserInfoSkeleton.module.css
│   │   │   │   │       │   │   ├── UserInfoSkeleton.tsx
│   │   │   │   │       │   │   └── index.ts
│   │   │   │   │       │   ├── UserStats/
│   │   │   │   │       │   │   ├── UserStats.module.css
│   │   │   │   │       │   │   ├── UserStats.tsx
│   │   │   │   │       │   │   └── index.ts
│   │   │   │   │       │   └── index.ts
│   │   │   │   │       ├── UserTabs/
│   │   │   │   │       │   ├── LikedTracksTab/
│   │   │   │   │       │   │   ├── LikedTracksTab.module.css
│   │   │   │   │       │   │   ├── LikedTracksTab.tsx
│   │   │   │   │       │   │   └── index.ts
│   │   │   │   │       │   ├── MyLikedPlaylistsTab/
│   │   │   │   │       │   │   ├── MyLikedPlaylistsTab.module.css
│   │   │   │   │       │   │   ├── MyLikedPlaylistsTab.tsx
│   │   │   │   │       │   │   └── index.ts
│   │   │   │   │       │   ├── PlaylistsTab/
│   │   │   │   │       │   │   ├── PlaylistsTab.module.css
│   │   │   │   │       │   │   ├── PlaylistsTab.tsx
│   │   │   │   │       │   │   └── index.ts
│   │   │   │   │       │   ├── TracksTab/
│   │   │   │   │       │   │   ├── TracksTab.module.css
│   │   │   │   │       │   │   ├── TracksTab.tsx
│   │   │   │   │       │   │   └── index.ts
│   │   │   │   │       │   ├── UserTabs.tsx
│   │   │   │   │       │   ├── UserTabsSkeleton/
│   │   │   │   │       │   │   ├── UserTabsSkeleton.module.css
│   │   │   │   │       │   │   ├── UserTabsSkeleton.tsx
│   │   │   │   │       │   │   └── index.ts
│   │   │   │   │       │   └── index.ts
│   │   │   │   │       └── index.ts
│   │   │   │   ├── common/
│   │   │   │   │   ├── hooks/
│   │   │   │   │   │   ├── index.ts
│   │   │   │   │   │   ├── usePageBackgroundColor.ts
│   │   │   │   │   │   └── usePageSearchParams.ts
│   │   │   │   │   ├── index.ts
│   │   │   │   │   └── ui/
│   │   │   │   │       ├── ContentList/
│   │   │   │   │       │   ├── ContentList.module.css
│   │   │   │   │       │   ├── ContentList.tsx
│   │   │   │   │       │   └── index.ts
│   │   │   │   │       ├── PageWithHeader/
│   │   │   │   │       │   ├── PageWithHeader.module.css
│   │   │   │   │       │   ├── PageWithHeader.tsx
│   │   │   │   │       │   └── index.ts
│   │   │   │   │       ├── PageWithoutHeader/
│   │   │   │   │       │   ├── PageWithoutHeader.module.css
│   │   │   │   │       │   ├── PageWithoutHeader.tsx
│   │   │   │   │       │   └── index.ts
│   │   │   │   │       ├── SearchTags/
│   │   │   │   │       │   ├── SearchTags.tsx
│   │   │   │   │       │   └── index.ts
│   │   │   │   │       ├── SearchTextField/
│   │   │   │   │       │   ├── SearchTextField.tsx
│   │   │   │   │       │   └── index.ts
│   │   │   │   │       └── SortSelect/
│   │   │   │   │           ├── SortSelect.module.css
│   │   │   │   │           ├── SortSelect.tsx
│   │   │   │   │           └── index.ts
│   │   │   │   └── index.ts
│   │   │   ├── player/
│   │   │   │   ├── MIGRATION_GUIDE.md
│   │   │   │   ├── README.md
│   │   │   │   ├── SPECIFICATION.md
│   │   │   │   ├── index.ts
│   │   │   │   ├── player.ts
│   │   │   │   ├── playerHooks.ts
│   │   │   │   ├── playerMiddleware.ts
│   │   │   │   ├── playerSelectors.ts
│   │   │   │   ├── playerSlice.ts
│   │   │   │   ├── task.md
│   │   │   │   ├── types/
│   │   │   │   │   └── player.types.ts
│   │   │   │   └── utils/
│   │   │   │       ├── convert-api-track-to-player-track.ts
│   │   │   │       ├── format-time.ts
│   │   │   │       ├── index.ts
│   │   │   │       ├── shuffle.ts
│   │   │   │       └── throttle.ts
│   │   │   ├── shared/
│   │   │   │   ├── assets/
│   │   │   │   │   └── images/
│   │   │   │   │       └── no-cover-placeholder.avif
│   │   │   │   ├── components/
│   │   │   │   │   ├── AudioPlayer/
│   │   │   │   │   │   ├── AudioPlayer.module.css
│   │   │   │   │   │   ├── AudioPlayer.stories.tsx
│   │   │   │   │   │   ├── AudioPlayer.tsx
│   │   │   │   │   │   ├── AudioPlayerSceleton/
│   │   │   │   │   │   │   ├── AudioPlayerSkeleton.module.css
│   │   │   │   │   │   │   ├── AudioPlayerSkeleton.stories.tsx
│   │   │   │   │   │   │   └── AudioPlayerSkeleton.tsx
│   │   │   │   │   │   └── index.ts
│   │   │   │   │   ├── Autocomplete/
│   │   │   │   │   │   ├── Autocomplete.module.css
│   │   │   │   │   │   ├── Autocomplete.stories.tsx
│   │   │   │   │   │   ├── Autocomplete.tsx
│   │   │   │   │   │   └── index.ts
│   │   │   │   │   ├── Avatar/
│   │   │   │   │   │   ├── Avatar.module.css
│   │   │   │   │   │   ├── Avatar.stories.tsx
│   │   │   │   │   │   ├── Avatar.tsx
│   │   │   │   │   │   └── index.ts
│   │   │   │   │   ├── Button/
│   │   │   │   │   │   ├── Button.module.css
│   │   │   │   │   │   ├── Button.stories.tsx
│   │   │   │   │   │   ├── Button.tsx
│   │   │   │   │   │   └── index.ts
│   │   │   │   │   ├── Card/
│   │   │   │   │   │   ├── Card.module.css
│   │   │   │   │   │   ├── Card.stories.tsx
│   │   │   │   │   │   ├── Card.tsx
│   │   │   │   │   │   └── index.ts
│   │   │   │   │   ├── Dialog/
│   │   │   │   │   │   ├── Dialog.module.css
│   │   │   │   │   │   ├── Dialog.stories.tsx
│   │   │   │   │   │   ├── Dialog.tsx
│   │   │   │   │   │   └── index.ts
│   │   │   │   │   ├── DropdownMenu/
│   │   │   │   │   │   ├── DropdownMenu.module.css
│   │   │   │   │   │   ├── DropdownMenu.stories.tsx
│   │   │   │   │   │   ├── DropdownMenu.tsx
│   │   │   │   │   │   └── index.ts
│   │   │   │   │   ├── FileUploader/
│   │   │   │   │   │   ├── FileUploader.module.css
│   │   │   │   │   │   ├── FileUploader.stories.tsx
│   │   │   │   │   │   ├── FileUploader.tsx
│   │   │   │   │   │   └── index.ts
│   │   │   │   │   ├── FormControlledTextField/
│   │   │   │   │   │   ├── FormControlledTextField.tsx
│   │   │   │   │   │   └── index.ts
│   │   │   │   │   ├── Hashtag/
│   │   │   │   │   │   ├── Tag.module.css
│   │   │   │   │   │   ├── Tag.stories.tsx
│   │   │   │   │   │   ├── Tag.tsx
│   │   │   │   │   │   └── index.ts
│   │   │   │   │   ├── IconButton/
│   │   │   │   │   │   ├── IconButton.module.css
│   │   │   │   │   │   ├── IconButton.stories.tsx
│   │   │   │   │   │   ├── IconButton.tsx
│   │   │   │   │   │   └── index.ts
│   │   │   │   │   ├── ImageCropper/
│   │   │   │   │   │   ├── ImageCropper.module.css
│   │   │   │   │   │   ├── ImageCropper.stories.tsx
│   │   │   │   │   │   ├── ImageCropper.tsx
│   │   │   │   │   │   └── index.ts
│   │   │   │   │   ├── ImageUploader/
│   │   │   │   │   │   ├── ImageUploader.module.css
│   │   │   │   │   │   ├── ImageUploader.stories.tsx
│   │   │   │   │   │   ├── ImageUploader.tsx
│   │   │   │   │   │   └── index.ts
│   │   │   │   │   ├── Loader/
│   │   │   │   │   │   ├── Loader.module.css
│   │   │   │   │   │   ├── Loader.tsx
│   │   │   │   │   │   └── index.ts
│   │   │   │   │   ├── Pagination/
│   │   │   │   │   │   ├── Pagination.module.css
│   │   │   │   │   │   ├── Pagination.stories.tsx
│   │   │   │   │   │   ├── Pagination.tsx
│   │   │   │   │   │   └── index.ts
│   │   │   │   │   ├── Progress/
│   │   │   │   │   │   ├── Progress.module.css
│   │   │   │   │   │   ├── Progress.stories.tsx
│   │   │   │   │   │   ├── Progress.tsx
│   │   │   │   │   │   └── index.ts
│   │   │   │   │   ├── ReactionButtons/
│   │   │   │   │   │   ├── ReactionButtons.module.css
│   │   │   │   │   │   ├── ReactionButtons.stories.tsx
│   │   │   │   │   │   ├── ReactionButtons.tsx
│   │   │   │   │   │   └── index.ts
│   │   │   │   │   ├── SearchField/
│   │   │   │   │   │   ├── SearchField.module.css
│   │   │   │   │   │   ├── SearchField.stories.tsx
│   │   │   │   │   │   ├── SearchField.tsx
│   │   │   │   │   │   └── index.ts
│   │   │   │   │   ├── Select/
│   │   │   │   │   │   ├── Select.module.css
│   │   │   │   │   │   ├── Select.stories.tsx
│   │   │   │   │   │   ├── Select.tsx
│   │   │   │   │   │   └── index.ts
│   │   │   │   │   ├── Skeleton/
│   │   │   │   │   │   ├── Skeleton.module.css
│   │   │   │   │   │   ├── Skeleton.stories.tsx
│   │   │   │   │   │   ├── Skeleton.tsx
│   │   │   │   │   │   └── index.ts
│   │   │   │   │   ├── SortSelect/
│   │   │   │   │   │   └── Select.tsx
│   │   │   │   │   ├── Spinner/
│   │   │   │   │   │   ├── Spinner.stories.tsx
│   │   │   │   │   │   ├── Spinner.tsx
│   │   │   │   │   │   └── spinner.module.css
│   │   │   │   │   ├── Table/
│   │   │   │   │   │   ├── Table.module.css
│   │   │   │   │   │   ├── Table.stories.tsx
│   │   │   │   │   │   ├── Table.tsx
│   │   │   │   │   │   └── index.ts
│   │   │   │   │   ├── Tabs/
│   │   │   │   │   │   ├── Tabs.module.css
│   │   │   │   │   │   ├── Tabs.stories.tsx
│   │   │   │   │   │   ├── Tabs.tsx
│   │   │   │   │   │   └── index.ts
│   │   │   │   │   ├── TagEditor/
│   │   │   │   │   │   ├── TagEditor.module.css
│   │   │   │   │   │   ├── TagEditor.stories.tsx
│   │   │   │   │   │   ├── TagEditor.tsx
│   │   │   │   │   │   └── index.ts
│   │   │   │   │   ├── TextField/
│   │   │   │   │   │   ├── TextField.module.css
│   │   │   │   │   │   ├── TextField.stories.tsx
│   │   │   │   │   │   ├── TextField.tsx
│   │   │   │   │   │   └── index.ts
│   │   │   │   │   ├── Textarea/
│   │   │   │   │   │   ├── Textarea.module.css
│   │   │   │   │   │   ├── Textarea.stories.tsx
│   │   │   │   │   │   ├── Textarea.tsx
│   │   │   │   │   │   └── index.ts
│   │   │   │   │   ├── Typography/
│   │   │   │   │   │   ├── Typography.module.css
│   │   │   │   │   │   ├── Typography.stories.tsx
│   │   │   │   │   │   ├── Typography.tsx
│   │   │   │   │   │   └── index.ts
│   │   │   │   │   └── index.ts
│   │   │   │   ├── configs/
│   │   │   │   │   ├── index.ts
│   │   │   │   │   └── paths.ts
│   │   │   │   ├── constants/
│   │   │   │   │   ├── constants.ts
│   │   │   │   │   └── index.ts
│   │   │   │   ├── hooks/
│   │   │   │   │   ├── index.ts
│   │   │   │   │   ├── useAppDispatch.ts
│   │   │   │   │   ├── useAppSelector.ts
│   │   │   │   │   ├── useCurrentPage.ts
│   │   │   │   │   ├── useDebounce.ts
│   │   │   │   │   ├── useGetId.ts
│   │   │   │   │   ├── useGlobalLoading.ts
│   │   │   │   │   └── useHover.ts
│   │   │   │   ├── icons/
│   │   │   │   │   ├── AddToPlaylistIcon.tsx
│   │   │   │   │   ├── AddTrackIcon.tsx
│   │   │   │   │   ├── ArrowBackIcon.tsx
│   │   │   │   │   ├── ArrowDownIcon.tsx
│   │   │   │   │   ├── CheckedIcon.tsx
│   │   │   │   │   ├── ClockIcon.tsx
│   │   │   │   │   ├── CreateIcon.tsx
│   │   │   │   │   ├── DeleteIcon.tsx
│   │   │   │   │   ├── DeleteTagIconButton.tsx
│   │   │   │   │   ├── DislikeIcon.tsx
│   │   │   │   │   ├── DownloadIcon.tsx
│   │   │   │   │   ├── EditIcon.tsx
│   │   │   │   │   ├── HomeIcon.tsx
│   │   │   │   │   ├── IconOneRepeat.tsx
│   │   │   │   │   ├── ImageUploadIcon.tsx
│   │   │   │   │   ├── KeyboardArrowLeftIcon.tsx
│   │   │   │   │   ├── KeyboardArrowRightIcon.tsx
│   │   │   │   │   ├── LanguageIcon.tsx
│   │   │   │   │   ├── LibraryIcon.tsx
│   │   │   │   │   ├── LikeIcon.tsx
│   │   │   │   │   ├── LikeIconFill.tsx
│   │   │   │   │   ├── LikeInSquareIcon.tsx
│   │   │   │   │   ├── LiveWaveIcon/
│   │   │   │   │   │   ├── LiveWaveIcon.module.css
│   │   │   │   │   │   ├── LiveWaveIcon.tsx
│   │   │   │   │   │   └── index.ts
│   │   │   │   │   ├── LogoutIcon.tsx
│   │   │   │   │   ├── MoreIcon.tsx
│   │   │   │   │   ├── PauseIcon.tsx
│   │   │   │   │   ├── PlayIcon.tsx
│   │   │   │   │   ├── PlaylistIcon.tsx
│   │   │   │   │   ├── PlusIcon.tsx
│   │   │   │   │   ├── ProfileIcon.tsx
│   │   │   │   │   ├── RepeatIcon.tsx
│   │   │   │   │   ├── SearchIcon.tsx
│   │   │   │   │   ├── ShuffleIcon.tsx
│   │   │   │   │   ├── SkipNextIcon.tsx
│   │   │   │   │   ├── SkipPreviousIcon.tsx
│   │   │   │   │   ├── StaticWaveIcon.tsx
│   │   │   │   │   ├── TextIcon.tsx
│   │   │   │   │   ├── TrackIcon.tsx
│   │   │   │   │   ├── UncheckedIcon.tsx
│   │   │   │   │   ├── UploadIcon.tsx
│   │   │   │   │   ├── VolumeIcon.tsx
│   │   │   │   │   ├── VolumeMuteIcon.tsx
│   │   │   │   │   └── index.ts
│   │   │   │   ├── translations/
│   │   │   │   │   ├── i18nConfiguration.ts
│   │   │   │   │   └── languages/
│   │   │   │   │       ├── en.json
│   │   │   │   │       └── ru.json
│   │   │   │   ├── types/
│   │   │   │   │   ├── common.types.ts
│   │   │   │   │   ├── commonApi.types.ts
│   │   │   │   │   └── index.ts
│   │   │   │   └── utils/
│   │   │   │       ├── build-query-string.ts
│   │   │   │       ├── convert-file-to-base-64.ts
│   │   │   │       ├── decode-file-from-base-64.ts
│   │   │   │       ├── format-created-date.ts
│   │   │   │       ├── get-image-by-type.ts
│   │   │   │       ├── get-plural-key.ts
│   │   │   │       ├── get-russian-plural-form.ts
│   │   │   │       ├── get-user-initials.ts
│   │   │   │       ├── index.ts
│   │   │   │       ├── set-locale.ts
│   │   │   │       └── show-error-toast.ts
│   │   │   ├── styles/
│   │   │   │   ├── fonts.css
│   │   │   │   ├── global.css
│   │   │   │   ├── reset.css
│   │   │   │   └── variables.css
│   │   │   ├── vite-env.d.ts
│   │   │   └── widgets/
│   │   │       └── Player/
│   │   │           ├── Player.module.css
│   │   │           ├── Player.tsx
│   │   │           └── index.ts
│   │   ├── stylelint.config.js
│   │   ├── tsconfig.app.json
│   │   ├── tsconfig.json
│   │   ├── tsconfig.node.json
│   │   └── vite.config.ts
│   ├── tanstack-query-zustand/
│   │   ├── .claude/
│   │   │   └── skills/
│   │   │       └── i18n-rules/
│   │   │           └── SKILL.md
│   │   ├── .gitignore
│   │   ├── .storybook/
│   │   │   ├── main.ts
│   │   │   └── preview.tsx
│   │   ├── AGENTS.md
│   │   ├── CLAUDE.md
│   │   ├── README.md
│   │   ├── eslint.config.js
│   │   ├── index.html
│   │   ├── package.json
│   │   ├── src/
│   │   │   ├── App.css
│   │   │   ├── App.tsx
│   │   │   ├── app/
│   │   │   │   ├── App.tsx
│   │   │   │   ├── entrypoint/
│   │   │   │   │   └── main.tsx
│   │   │   │   ├── query-client/
│   │   │   │   │   └── query-client.tsx
│   │   │   │   ├── routing/
│   │   │   │   │   ├── Routing.tsx
│   │   │   │   │   └── index.ts
│   │   │   │   └── styles/
│   │   │   │       ├── fonts.css
│   │   │   │       ├── global.css
│   │   │   │       ├── reset.css
│   │   │   │       └── variables.css
│   │   │   ├── assets/
│   │   │   │   └── img/
│   │   │   │       └── no-cover-placeholder.avif
│   │   │   ├── entities/
│   │   │   │   └── playlist/
│   │   │   │       ├── index.tsx
│   │   │   │       └── ui/
│   │   │   │           ├── PlaylistCard/
│   │   │   │           │   ├── PlaylistCard.module.scss
│   │   │   │           │   ├── PlaylistCard.stories.tsx
│   │   │   │           │   ├── PlaylistCard.tsx
│   │   │   │           │   └── index.ts
│   │   │   │           ├── PlaylistCardSkeleton/
│   │   │   │           │   ├── PlaylistCardSkeleton.tsx
│   │   │   │           │   └── index.ts
│   │   │   │           └── PlaylistItem/
│   │   │   │               ├── PlaylistItem.tsx
│   │   │   │               ├── PlaylistItem.types.ts
│   │   │   │               └── index.ts
│   │   │   ├── features/
│   │   │   │   ├── artists/
│   │   │   │   │   ├── api/
│   │   │   │   │   │   ├── artists-api.ts
│   │   │   │   │   │   ├── index.ts
│   │   │   │   │   │   └── use-artists.query.ts
│   │   │   │   │   ├── index.ts
│   │   │   │   │   └── ui/
│   │   │   │   │       └── ArtistCard/
│   │   │   │   │           ├── ArtistCard.module.css
│   │   │   │   │           ├── ArtistCard.stories.tsx
│   │   │   │   │           ├── ArtistCard.tsx
│   │   │   │   │           └── index.ts
│   │   │   │   ├── auth/
│   │   │   │   │   ├── api/
│   │   │   │   │   │   ├── use-login.mutation.ts
│   │   │   │   │   │   ├── use-logout.mutation.ts
│   │   │   │   │   │   └── use-me.query.ts
│   │   │   │   │   ├── index.ts
│   │   │   │   │   ├── types/
│   │   │   │   │   │   └── auth-api.types.ts
│   │   │   │   │   └── ui/
│   │   │   │   │       ├── LoginButtonAndModal/
│   │   │   │   │       │   ├── LoginButtonAndModal.tsx
│   │   │   │   │       │   └── index.ts
│   │   │   │   │       ├── LoginModal/
│   │   │   │   │       │   ├── LoginModal.module.css
│   │   │   │   │       │   ├── LoginModal.tsx
│   │   │   │   │       │   └── index.ts
│   │   │   │   │       ├── ProfileDropdownMenu/
│   │   │   │   │       │   ├── ProfileDropdownMenu.module.css
│   │   │   │   │       │   ├── ProfileDropdownMenu.stories.tsx
│   │   │   │   │       │   ├── ProfileDropdownMenu.tsx
│   │   │   │   │       │   └── index.ts
│   │   │   │   │       └── index.ts
│   │   │   │   ├── playlists/
│   │   │   │   │   ├── api/
│   │   │   │   │   │   ├── index.ts
│   │   │   │   │   │   ├── playlistsApi.ts
│   │   │   │   │   │   ├── query-key-factory.ts
│   │   │   │   │   │   ├── types.ts
│   │   │   │   │   │   ├── use-playlist-mutations.ts
│   │   │   │   │   │   ├── use-playlist.query.ts
│   │   │   │   │   │   └── use-playlists.query.ts
│   │   │   │   │   ├── index.ts
│   │   │   │   │   ├── model/
│   │   │   │   │   │   └── usePlaylistReactions.ts
│   │   │   │   │   └── ui/
│   │   │   │   │       ├── ChoosePlaylistModal/
│   │   │   │   │       │   ├── ChoosePlaylistModal.module.css
│   │   │   │   │       │   └── ChoosePlaylistModal.tsx
│   │   │   │   │       ├── CreatePlaylistModal/
│   │   │   │   │       │   ├── CreatePlaylistModal.module.css
│   │   │   │   │       │   ├── CreatePlaylistModal.tsx
│   │   │   │   │       │   └── index.ts
│   │   │   │   │       ├── PlaylistOverview/
│   │   │   │   │       │   ├── PlaylistOverview.module.css
│   │   │   │   │       │   ├── PlaylistOverview.stories.tsx
│   │   │   │   │       │   ├── PlaylistOverview.tsx
│   │   │   │   │       │   └── index.ts
│   │   │   │   │       ├── PlaylistRow/
│   │   │   │   │       │   ├── PlaylistRow.module.css
│   │   │   │   │       │   ├── PlaylistRow.tsx
│   │   │   │   │       │   └── index.ts
│   │   │   │   │       └── index.ts
│   │   │   │   ├── profile/
│   │   │   │   │   ├── config/
│   │   │   │   │   │   ├── empty-profile.ts
│   │   │   │   │   │   └── index.ts
│   │   │   │   │   ├── index.ts
│   │   │   │   │   ├── model/
│   │   │   │   │   │   ├── hooks/
│   │   │   │   │   │   │   ├── index.ts
│   │   │   │   │   │   │   ├── use-edit-profile-modal.ts
│   │   │   │   │   │   │   ├── use-edit-profile-schema.ts
│   │   │   │   │   │   │   └── use-hydrate-profile.ts
│   │   │   │   │   │   ├── index.ts
│   │   │   │   │   │   ├── profile-schemas.ts
│   │   │   │   │   │   └── profile-store.ts
│   │   │   │   │   ├── types/
│   │   │   │   │   │   ├── index.ts
│   │   │   │   │   │   └── profile.types.ts
│   │   │   │   │   ├── ui/
│   │   │   │   │   │   ├── EditProfileModal/
│   │   │   │   │   │   │   ├── EditProfileModal.module.css
│   │   │   │   │   │   │   ├── EditProfileModal.tsx
│   │   │   │   │   │   │   └── index.ts
│   │   │   │   │   │   └── index.ts
│   │   │   │   │   └── utils/
│   │   │   │   │       ├── index.ts
│   │   │   │   │       ├── profile-storage.ts
│   │   │   │   │       └── storage-key.ts
│   │   │   │   ├── tags/
│   │   │   │   │   ├── api/
│   │   │   │   │   │   ├── index.ts
│   │   │   │   │   │   ├── tags-api.ts
│   │   │   │   │   │   └── use-tags.query.ts
│   │   │   │   │   ├── index.ts
│   │   │   │   │   └── ui/
│   │   │   │   │       ├── TagsList/
│   │   │   │   │       │   ├── TagsList.module.css
│   │   │   │   │       │   ├── TagsList.stories.tsx
│   │   │   │   │       │   ├── TagsList.tsx
│   │   │   │   │       │   └── index.ts
│   │   │   │   │       └── index.ts
│   │   │   │   └── tracks/
│   │   │   │       ├── api/
│   │   │   │       │   ├── index.ts
│   │   │   │       │   ├── query-key-factory.ts
│   │   │   │       │   ├── tracksApi.ts
│   │   │   │       │   ├── types.ts
│   │   │   │       │   ├── use-playlist-tracks.query.ts
│   │   │   │       │   ├── use-track-mutations.ts
│   │   │   │       │   ├── use-track.query.ts
│   │   │   │       │   └── use-tracks.query.ts
│   │   │   │       ├── index.ts
│   │   │   │       ├── model/
│   │   │   │       │   └── useTrackReactions.ts
│   │   │   │       ├── ui/
│   │   │   │       │   ├── CreateTrackForm/
│   │   │   │       │   │   ├── CreateTrackModal.module.css
│   │   │   │       │   │   └── CreateTrackModal.tsx
│   │   │   │       │   ├── TrackActions/
│   │   │   │       │   │   ├── TrackActions.tsx
│   │   │   │       │   │   └── index.ts
│   │   │   │       │   ├── TrackActionsMenu/
│   │   │   │       │   │   └── TrackActionsMenu.tsx
│   │   │   │       │   ├── TrackCard/
│   │   │   │       │   │   ├── TrackCard.module.css
│   │   │   │       │   │   ├── TrackCard.stories.tsx
│   │   │   │       │   │   ├── TrackCard.tsx
│   │   │   │       │   │   └── index.ts
│   │   │   │       │   ├── TrackInfoCell/
│   │   │   │       │   │   ├── TrackInfoCell.module.css
│   │   │   │       │   │   ├── TrackInfoCell.tsx
│   │   │   │       │   │   └── index.ts
│   │   │   │       │   ├── TrackOverview/
│   │   │   │       │   │   ├── TrackOverview.module.css
│   │   │   │       │   │   ├── TrackOverview.stories.tsx
│   │   │   │       │   │   ├── TrackOverview.tsx
│   │   │   │       │   │   └── index.ts
│   │   │   │       │   ├── TrackRow/
│   │   │   │       │   │   ├── TrackRow.module.css
│   │   │   │       │   │   └── TrackRow.tsx
│   │   │   │       │   ├── TrackRowContainer/
│   │   │   │       │   │   ├── TrackRowContainer.module.css
│   │   │   │       │   │   └── TrackRowContainer.tsx
│   │   │   │       │   ├── TracksTable/
│   │   │   │       │   │   ├── TrackTable.stories.tsx
│   │   │   │       │   │   ├── TracksTable.tsx
│   │   │   │       │   │   └── index.ts
│   │   │   │       │   ├── TracksTableSkeleton/
│   │   │   │       │   │   ├── TracksTableSkeleton.tsx
│   │   │   │       │   │   └── index.ts
│   │   │   │       │   └── index.ts
│   │   │   │       └── utils/
│   │   │   │           └── playlistSync.ts
│   │   │   ├── index.css
│   │   │   ├── layout/
│   │   │   │   ├── Header/
│   │   │   │   │   ├── Header.module.css
│   │   │   │   │   ├── Header.tsx
│   │   │   │   │   └── index.ts
│   │   │   │   ├── Layout.module.css
│   │   │   │   ├── Layout.tsx
│   │   │   │   ├── Sidebar/
│   │   │   │   │   ├── MenuLinks/
│   │   │   │   │   │   ├── MenuLinks.module.css
│   │   │   │   │   │   ├── MenuLinks.tsx
│   │   │   │   │   │   └── index.ts
│   │   │   │   │   ├── Sidebar.module.css
│   │   │   │   │   ├── Sidebar.tsx
│   │   │   │   │   └── index.ts
│   │   │   │   └── index.ts
│   │   │   ├── main.tsx
│   │   │   ├── pages/
│   │   │   │   ├── MainPage/
│   │   │   │   │   ├── MainPage.module.css
│   │   │   │   │   ├── MainPage.tsx
│   │   │   │   │   └── index.ts
│   │   │   │   ├── PlaylistPage/
│   │   │   │   │   ├── PlaylistPage.module.css
│   │   │   │   │   ├── PlaylistPage.tsx
│   │   │   │   │   ├── index.ts
│   │   │   │   │   └── ui/
│   │   │   │   │       ├── ControlPanel/
│   │   │   │   │       │   ├── ControlPanel.module.scss
│   │   │   │   │       │   ├── ControlPanel.tsx
│   │   │   │   │       │   └── index.ts
│   │   │   │   │       └── PlaylistPageSkeleton/
│   │   │   │   │           ├── PlaylistPageSkeleton.module.css
│   │   │   │   │           ├── PlaylistPageSkeleton.tsx
│   │   │   │   │           └── index.ts
│   │   │   │   ├── PlaylistsPage/
│   │   │   │   │   ├── PlaylistsPage.module.css
│   │   │   │   │   ├── PlaylistsPage.tsx
│   │   │   │   │   ├── PlaylistsPage.types.ts
│   │   │   │   │   ├── index.ts
│   │   │   │   │   └── model/
│   │   │   │   │       ├── useCreatePlaylist.ts
│   │   │   │   │       ├── useDeletePlaylist.ts
│   │   │   │   │       └── useUploadPlaylistCover.ts
│   │   │   │   ├── TrackLyricsPage/
│   │   │   │   │   ├── TrackLyricsPage.module.css
│   │   │   │   │   ├── TrackLyricsPage.tsx
│   │   │   │   │   └── index.ts
│   │   │   │   ├── TrackPage/
│   │   │   │   │   ├── TrackPage.module.css
│   │   │   │   │   ├── TrackPage.tsx
│   │   │   │   │   ├── index.ts
│   │   │   │   │   └── ui/
│   │   │   │   │       ├── ControlPanel/
│   │   │   │   │       │   ├── ControlPanel.module.css
│   │   │   │   │       │   ├── ControlPanel.tsx
│   │   │   │   │       │   └── index.ts
│   │   │   │   │       └── TrackPageSkeleton/
│   │   │   │   │           ├── TrackPageSkeleton.module.css
│   │   │   │   │           ├── TrackPageSkeleton.tsx
│   │   │   │   │           └── index.ts
│   │   │   │   ├── TracksPage/
│   │   │   │   │   ├── TracksPage.module.css
│   │   │   │   │   ├── TracksPage.tsx
│   │   │   │   │   ├── TracksSortFunction.ts
│   │   │   │   │   ├── index.ts
│   │   │   │   │   ├── model/
│   │   │   │   │   │   ├── useTrackDetails.ts
│   │   │   │   │   │   ├── useTracksInfinityQuery.ts
│   │   │   │   │   │   ├── useTracksQuery.tsx
│   │   │   │   │   │   ├── useUploadTrack.ts
│   │   │   │   │   │   └── useUploadTrackCover.ts
│   │   │   │   │   └── tracksPageTypes/
│   │   │   │   │       └── TracksPageTypes.ts
│   │   │   │   ├── UserPage/
│   │   │   │   │   ├── UserPage.module.css
│   │   │   │   │   ├── UserPage.tsx
│   │   │   │   │   ├── hooks/
│   │   │   │   │   │   ├── index.ts
│   │   │   │   │   │   ├── useUserPageBackgroundColor.ts
│   │   │   │   │   │   └── useUserPageData.ts
│   │   │   │   │   ├── index.ts
│   │   │   │   │   └── ui/
│   │   │   │   │       ├── UserInfo/
│   │   │   │   │       │   ├── UserInfo.module.css
│   │   │   │   │       │   ├── UserInfo.tsx
│   │   │   │   │       │   ├── UserInfoSkeleton.module.css
│   │   │   │   │       │   ├── UserInfoSkeleton.tsx
│   │   │   │   │       │   ├── UserStats.module.css
│   │   │   │   │       │   ├── UserStats.tsx
│   │   │   │   │       │   └── index.ts
│   │   │   │   │       ├── UserTabs/
│   │   │   │   │       │   ├── LikedTracksTab/
│   │   │   │   │       │   │   ├── LikedTracksTab.module.css
│   │   │   │   │       │   │   ├── LikedTracksTab.tsx
│   │   │   │   │       │   │   └── index.ts
│   │   │   │   │       │   ├── MyLikedPlaylistsTab/
│   │   │   │   │       │   │   ├── MyLikedPlaylistsTab.module.css
│   │   │   │   │       │   │   ├── MyLikedPlaylistsTab.tsx
│   │   │   │   │       │   │   └── index.ts
│   │   │   │   │       │   ├── PlaylistsTab/
│   │   │   │   │       │   │   ├── PlaylistsTab.module.css
│   │   │   │   │       │   │   ├── PlaylistsTab.tsx
│   │   │   │   │       │   │   └── index.ts
│   │   │   │   │       │   ├── TracksTab/
│   │   │   │   │       │   │   ├── TracksTab.module.css
│   │   │   │   │       │   │   ├── TracksTab.tsx
│   │   │   │   │       │   │   └── index.ts
│   │   │   │   │       │   ├── UserTabs.tsx
│   │   │   │   │       │   ├── UserTabsSkeleton/
│   │   │   │   │       │   │   ├── UserTabsSkeleton.module.css
│   │   │   │   │       │   │   ├── UserTabsSkeleton.tsx
│   │   │   │   │       │   │   └── index.ts
│   │   │   │   │       │   └── index.ts
│   │   │   │   │       └── index.ts
│   │   │   │   ├── auth/
│   │   │   │   │   └── OAuthRedirect/
│   │   │   │   │       ├── OAuthCallback.module.css
│   │   │   │   │       └── OAuthCallback.tsx
│   │   │   │   ├── common/
│   │   │   │   │   ├── ContentList/
│   │   │   │   │   │   ├── ContentList.module.css
│   │   │   │   │   │   ├── ContentList.tsx
│   │   │   │   │   │   └── index.ts
│   │   │   │   │   ├── PageWithHeader/
│   │   │   │   │   │   ├── PageWithHeader.module.css
│   │   │   │   │   │   └── PageWithHeader.tsx
│   │   │   │   │   ├── PageWithoutHeader/
│   │   │   │   │   │   ├── PageWithoutHeader.module.css
│   │   │   │   │   │   └── PageWithoutHeader.tsx
│   │   │   │   │   ├── PageWrapper/
│   │   │   │   │   │   ├── PageWrapper.module.css
│   │   │   │   │   │   ├── PageWrapper.tsx
│   │   │   │   │   │   └── index.ts
│   │   │   │   │   ├── SearchTextField/
│   │   │   │   │   │   ├── SearchTextField.tsx
│   │   │   │   │   │   └── index.ts
│   │   │   │   │   ├── SortSelect/
│   │   │   │   │   │   ├── SortSelect.module.css
│   │   │   │   │   │   ├── SortSelect.tsx
│   │   │   │   │   │   └── index.ts
│   │   │   │   │   └── index.ts
│   │   │   │   └── index.ts
│   │   │   ├── player/
│   │   │   │   ├── README.md
│   │   │   │   ├── SPECIFICATION.md
│   │   │   │   ├── index.ts
│   │   │   │   ├── model/
│   │   │   │   │   ├── audio-manager.ts
│   │   │   │   │   ├── player-hooks.ts
│   │   │   │   │   ├── player-store.ts
│   │   │   │   │   └── player-track-hooks.ts
│   │   │   │   ├── task.md
│   │   │   │   ├── types/
│   │   │   │   │   └── player.types.ts
│   │   │   │   └── utils/
│   │   │   │       ├── convert-api-track-to-player-track.ts
│   │   │   │       ├── format-time.ts
│   │   │   │       ├── index.ts
│   │   │   │       ├── shuffle.ts
│   │   │   │       └── track-navigation.ts
│   │   │   ├── shared/
│   │   │   │   ├── api/
│   │   │   │   │   ├── client.ts
│   │   │   │   │   ├── schema.ts
│   │   │   │   │   ├── types.ts
│   │   │   │   │   └── utils/
│   │   │   │   │       ├── json-api-error.ts
│   │   │   │   │       └── unwrap.ts
│   │   │   │   ├── auth/
│   │   │   │   │   └── types/
│   │   │   │   │       └── local-storage.keys.ts
│   │   │   │   ├── components/
│   │   │   │   │   ├── AudioPlayer/
│   │   │   │   │   │   ├── AudioPlayer.module.css
│   │   │   │   │   │   ├── AudioPlayer.stories.tsx
│   │   │   │   │   │   ├── AudioPlayer.tsx
│   │   │   │   │   │   └── index.ts
│   │   │   │   │   ├── Autocomplete/
│   │   │   │   │   │   ├── Autocomplete.module.css
│   │   │   │   │   │   ├── Autocomplete.stories.tsx
│   │   │   │   │   │   ├── Autocomplete.tsx
│   │   │   │   │   │   └── index.ts
│   │   │   │   │   ├── Avatar/
│   │   │   │   │   │   ├── Avatar.module.css
│   │   │   │   │   │   ├── Avatar.tsx
│   │   │   │   │   │   └── index.ts
│   │   │   │   │   ├── Button/
│   │   │   │   │   │   ├── Button.module.css
│   │   │   │   │   │   ├── Button.stories.tsx
│   │   │   │   │   │   ├── Button.tsx
│   │   │   │   │   │   └── index.ts
│   │   │   │   │   ├── Card/
│   │   │   │   │   │   ├── Card.module.css
│   │   │   │   │   │   ├── Card.stories.tsx
│   │   │   │   │   │   ├── Card.tsx
│   │   │   │   │   │   └── index.ts
│   │   │   │   │   ├── CoverImage/
│   │   │   │   │   │   ├── CoverImage.styles.module.scss
│   │   │   │   │   │   ├── CoverImage.tsx
│   │   │   │   │   │   └── index.ts
│   │   │   │   │   ├── Dialog/
│   │   │   │   │   │   ├── Dialog.module.css
│   │   │   │   │   │   ├── Dialog.stories.tsx
│   │   │   │   │   │   ├── Dialog.tsx
│   │   │   │   │   │   └── index.ts
│   │   │   │   │   ├── DropdownMenu/
│   │   │   │   │   │   ├── DropdownMenu.module.scss
│   │   │   │   │   │   ├── DropdownMenu.stories.tsx
│   │   │   │   │   │   ├── DropdownMenu.tsx
│   │   │   │   │   │   └── index.ts
│   │   │   │   │   ├── FormControlledTextField/
│   │   │   │   │   │   ├── FormControlledTextField.tsx
│   │   │   │   │   │   └── index.ts
│   │   │   │   │   ├── Hashtag/
│   │   │   │   │   │   ├── Tag.module.css
│   │   │   │   │   │   ├── Tag.stories.tsx
│   │   │   │   │   │   ├── Tag.tsx
│   │   │   │   │   │   └── index.ts
│   │   │   │   │   ├── IconButton/
│   │   │   │   │   │   ├── IconButton.module.css
│   │   │   │   │   │   ├── IconButton.stories.tsx
│   │   │   │   │   │   ├── IconButton.tsx
│   │   │   │   │   │   └── index.ts
│   │   │   │   │   ├── ImageCropper/
│   │   │   │   │   │   ├── ImageCropper.module.css
│   │   │   │   │   │   ├── ImageCropper.tsx
│   │   │   │   │   │   └── index.ts
│   │   │   │   │   ├── ImageUploader/
│   │   │   │   │   │   ├── ImageUploader.module.css
│   │   │   │   │   │   ├── ImageUploader.stories.tsx
│   │   │   │   │   │   ├── ImageUploader.tsx
│   │   │   │   │   │   └── index.ts
│   │   │   │   │   ├── LanguageSwitcher/
│   │   │   │   │   │   ├── LanguageSwitcher.tsx
│   │   │   │   │   │   └── index.ts
│   │   │   │   │   ├── Pagination/
│   │   │   │   │   │   ├── Pagination.module.css
│   │   │   │   │   │   ├── Pagination.stories.tsx
│   │   │   │   │   │   ├── Pagination.tsx
│   │   │   │   │   │   └── index.ts
│   │   │   │   │   ├── Progress/
│   │   │   │   │   │   ├── Progress.module.css
│   │   │   │   │   │   ├── Progress.stories.tsx
│   │   │   │   │   │   ├── Progress.tsx
│   │   │   │   │   │   └── index.ts
│   │   │   │   │   ├── ReactionButtons/
│   │   │   │   │   │   ├── ReactionButtons.module.css
│   │   │   │   │   │   ├── ReactionButtons.stories.tsx
│   │   │   │   │   │   ├── ReactionButtons.tsx
│   │   │   │   │   │   └── index.ts
│   │   │   │   │   ├── SearchField/
│   │   │   │   │   │   ├── SearchField.module.css
│   │   │   │   │   │   ├── SearchField.stories.tsx
│   │   │   │   │   │   ├── SearchField.tsx
│   │   │   │   │   │   └── index.ts
│   │   │   │   │   ├── Select/
│   │   │   │   │   │   ├── Select.module.css
│   │   │   │   │   │   ├── Select.stories.tsx
│   │   │   │   │   │   ├── Select.tsx
│   │   │   │   │   │   └── index.ts
│   │   │   │   │   ├── Skeleton/
│   │   │   │   │   │   ├── Skeleton.module.css
│   │   │   │   │   │   ├── Skeleton.tsx
│   │   │   │   │   │   └── index.ts
│   │   │   │   │   ├── SortSelect/
│   │   │   │   │   │   └── Select.tsx
│   │   │   │   │   ├── Spinner/
│   │   │   │   │   │   ├── Spinner.stories.tsx
│   │   │   │   │   │   ├── Spinner.tsx
│   │   │   │   │   │   ├── index.ts
│   │   │   │   │   │   └── spinner.module.css
│   │   │   │   │   ├── Table/
│   │   │   │   │   │   ├── Table.module.css
│   │   │   │   │   │   ├── Table.stories.tsx
│   │   │   │   │   │   ├── Table.tsx
│   │   │   │   │   │   └── index.ts
│   │   │   │   │   ├── Tabs/
│   │   │   │   │   │   ├── Tabs.module.css
│   │   │   │   │   │   ├── Tabs.stories.tsx
│   │   │   │   │   │   ├── Tabs.tsx
│   │   │   │   │   │   └── index.ts
│   │   │   │   │   ├── TagEditor/
│   │   │   │   │   │   ├── TagEditor.module.css
│   │   │   │   │   │   ├── TagEditor.stories.tsx
│   │   │   │   │   │   ├── TagEditor.tsx
│   │   │   │   │   │   └── index.ts
│   │   │   │   │   ├── TextField/
│   │   │   │   │   │   ├── TextField.module.css
│   │   │   │   │   │   ├── TextField.stories.tsx
│   │   │   │   │   │   ├── TextField.tsx
│   │   │   │   │   │   └── index.ts
│   │   │   │   │   ├── Textarea/
│   │   │   │   │   │   ├── Textarea.module.css
│   │   │   │   │   │   ├── Textarea.stories.tsx
│   │   │   │   │   │   ├── Textarea.tsx
│   │   │   │   │   │   └── index.ts
│   │   │   │   │   ├── Typography/
│   │   │   │   │   │   ├── Typography.module.css
│   │   │   │   │   │   ├── Typography.stories.tsx
│   │   │   │   │   │   ├── Typography.tsx
│   │   │   │   │   │   └── index.ts
│   │   │   │   │   └── index.ts
│   │   │   │   ├── config/
│   │   │   │   │   ├── config.ts
│   │   │   │   │   └── paths.ts
│   │   │   │   ├── featureFlags.ts
│   │   │   │   ├── hooks/
│   │   │   │   │   ├── debounceCallback/
│   │   │   │   │   │   ├── index.ts
│   │   │   │   │   │   ├── useDebounceCallback.ts
│   │   │   │   │   │   └── useDebounceCallback.types.ts
│   │   │   │   │   ├── debounceValue/
│   │   │   │   │   │   ├── index.ts
│   │   │   │   │   │   └── useDebounceValue.ts
│   │   │   │   │   ├── getId/
│   │   │   │   │   │   ├── index.ts
│   │   │   │   │   │   └── useGetId.ts
│   │   │   │   │   ├── index.ts
│   │   │   │   │   ├── throttleCallback/
│   │   │   │   │   │   ├── index.ts
│   │   │   │   │   │   ├── useThrottleCallback.tsx
│   │   │   │   │   │   └── useThrottleCallback.types.ts
│   │   │   │   │   ├── useCurrentPage.ts
│   │   │   │   │   ├── useDeletePlaylistAction.ts
│   │   │   │   │   ├── useEntityReactions.ts
│   │   │   │   │   ├── useHover.ts
│   │   │   │   │   ├── usePageBackgroundColor.ts
│   │   │   │   │   └── usePageSearchParams.ts
│   │   │   │   ├── icons/
│   │   │   │   │   ├── AddToPlaylistIcon.tsx
│   │   │   │   │   ├── ArrowBackIcon.tsx
│   │   │   │   │   ├── ArrowDownIcon.tsx
│   │   │   │   │   ├── CheckedIcon.tsx
│   │   │   │   │   ├── ClockIcon.tsx
│   │   │   │   │   ├── CreateIcon.tsx
│   │   │   │   │   ├── DeleteIcon.tsx
│   │   │   │   │   ├── DeleteTagIconButton.tsx
│   │   │   │   │   ├── DislikeIcon.tsx
│   │   │   │   │   ├── DownloadIcon.tsx
│   │   │   │   │   ├── EditIcon.tsx
│   │   │   │   │   ├── HomeIcon.tsx
│   │   │   │   │   ├── ImageUploadIcon.tsx
│   │   │   │   │   ├── KeyboardArrowLeftIcon.tsx
│   │   │   │   │   ├── KeyboardArrowRightIcon.tsx
│   │   │   │   │   ├── LanguageIcon.tsx
│   │   │   │   │   ├── LibraryIcon.tsx
│   │   │   │   │   ├── LikeIcon.tsx
│   │   │   │   │   ├── LikeIconFill.tsx
│   │   │   │   │   ├── LikeInSquareIcon.tsx
│   │   │   │   │   ├── LiveWaveIcon/
│   │   │   │   │   │   ├── LiveWaveIcon.module.css
│   │   │   │   │   │   ├── LiveWaveIcon.tsx
│   │   │   │   │   │   └── index.ts
│   │   │   │   │   ├── LogoutIcon.tsx
│   │   │   │   │   ├── MoreIcon.tsx
│   │   │   │   │   ├── PauseIcon.tsx
│   │   │   │   │   ├── PlayIcon.tsx
│   │   │   │   │   ├── PlaylistIcon.tsx
│   │   │   │   │   ├── PlusIcon.tsx
│   │   │   │   │   ├── ProfileIcon.tsx
│   │   │   │   │   ├── RepeatIcon.tsx
│   │   │   │   │   ├── SearchIcon.tsx
│   │   │   │   │   ├── ShuffleIcon.tsx
│   │   │   │   │   ├── SkipNextIcon.tsx
│   │   │   │   │   ├── SkipPreviousIcon.tsx
│   │   │   │   │   ├── TextIcon.tsx
│   │   │   │   │   ├── TrackIcon.tsx
│   │   │   │   │   ├── UncheckedIcon.tsx
│   │   │   │   │   ├── UploadIcon.tsx
│   │   │   │   │   ├── VolumeIcon.tsx
│   │   │   │   │   ├── VolumeMuteIcon.tsx
│   │   │   │   │   └── index.ts
│   │   │   │   ├── model/
│   │   │   │   │   └── ui-store.ts
│   │   │   │   ├── translations/
│   │   │   │   │   ├── i18nConfiguration.ts
│   │   │   │   │   └── languages/
│   │   │   │   │       ├── en.json
│   │   │   │   │       └── ru.json
│   │   │   │   ├── types/
│   │   │   │   │   ├── api-track.types.ts
│   │   │   │   │   └── strict.tsx
│   │   │   │   ├── ui/
│   │   │   │   │   ├── prerender-ready.tsx
│   │   │   │   │   └── utils/
│   │   │   │   │       └── query-error-handler-for-rhf-factory.ts
│   │   │   │   └── utils/
│   │   │   │       ├── authStorage.ts
│   │   │   │       ├── decode-file-from-base-64.ts
│   │   │   │       ├── format-created-date.ts
│   │   │   │       ├── get-artist-id.ts
│   │   │   │       ├── get-artist-name.ts
│   │   │   │       ├── get-artists-by-track.ts
│   │   │   │       ├── get-audio-url.ts
│   │   │   │       ├── get-cover-url.ts
│   │   │   │       ├── get-image-by-type.ts
│   │   │   │       ├── get-plural-key.ts
│   │   │   │       ├── get-russian-plural-form.ts
│   │   │   │       ├── get-user-initials.ts
│   │   │   │       ├── index.ts
│   │   │   │       ├── join-url.test.ts
│   │   │   │       ├── join-url.ts
│   │   │   │       ├── set-locale.ts
│   │   │   │       └── validators/
│   │   │   │           ├── getType.ts
│   │   │   │           ├── inNun.ts
│   │   │   │           ├── index.ts
│   │   │   │           ├── isArray.ts
│   │   │   │           ├── isFunction.ts
│   │   │   │           ├── isNotEmptyArray.ts
│   │   │   │           ├── isNull.ts
│   │   │   │           ├── isNumber.ts
│   │   │   │           ├── isObject.ts
│   │   │   │           ├── isString.ts
│   │   │   │           ├── isUndefined.ts
│   │   │   │           ├── isValid.ts
│   │   │   │           ├── isValidNumber.ts
│   │   │   │           ├── isValidObject.ts
│   │   │   │           └── isValidString.ts
│   │   │   └── widgets/
│   │   │       └── Player/
│   │   │           ├── Player.module.css
│   │   │           ├── Player.tsx
│   │   │           └── index.ts
│   │   ├── stylelint.config.js
│   │   ├── tsconfig.app.json
│   │   ├── tsconfig.json
│   │   ├── tsconfig.node.json
│   │   └── vite.config.ts
│   └── ui-vanilla/
│       ├── .gitignore
│       ├── .storybook/
│       │   ├── main.ts
│       │   └── preview.tsx
│       ├── README.md
│       ├── eslint.config.js
│       ├── index.html
│       ├── package.json
│       ├── src/
│       │   ├── app/
│       │   │   ├── App.tsx
│       │   │   └── routing/
│       │   │       ├── Routing.tsx
│       │   │       └── index.ts
│       │   ├── features/
│       │   │   ├── artists/
│       │   │   │   ├── api/
│       │   │   │   │   ├── artists-api.ts
│       │   │   │   │   └── index.ts
│       │   │   │   ├── index.ts
│       │   │   │   └── ui/
│       │   │   │       └── ArtistCard/
│       │   │   │           ├── ArtistCard.module.css
│       │   │   │           ├── ArtistCard.stories.tsx
│       │   │   │           ├── ArtistCard.tsx
│       │   │   │           └── index.ts
│       │   │   ├── auth/
│       │   │   │   ├── index.ts
│       │   │   │   └── ui/
│       │   │   │       ├── LoginButtonAndModal/
│       │   │   │       │   ├── LoginButtonAndModal.module.css
│       │   │   │       │   ├── LoginButtonAndModal.tsx
│       │   │   │       │   └── index.ts
│       │   │   │       ├── ProfileDropdownMenu/
│       │   │   │       │   ├── ProfileDropdownMenu.module.css
│       │   │   │       │   ├── ProfileDropdownMenu.stories.tsx
│       │   │   │       │   ├── ProfileDropdownMenu.tsx
│       │   │   │       │   └── index.ts
│       │   │   │       └── index.ts
│       │   │   ├── playlists/
│       │   │   │   ├── api/
│       │   │   │   │   ├── index.ts
│       │   │   │   │   └── playlistsApi.ts
│       │   │   │   ├── index.ts
│       │   │   │   └── ui/
│       │   │   │       ├── CreatePlaylistModal/
│       │   │   │       │   ├── CreatePlaylistModal.module.css
│       │   │   │       │   ├── CreatePlaylistModal.tsx
│       │   │   │       │   └── index.ts
│       │   │   │       ├── PlaylistCard/
│       │   │   │       │   ├── PlaylistCard.module.css
│       │   │   │       │   ├── PlaylistCard.stories.tsx
│       │   │   │       │   ├── PlaylistCard.tsx
│       │   │   │       │   └── index.ts
│       │   │   │       ├── PlaylistOverview/
│       │   │   │       │   ├── PlaylistOverview.module.css
│       │   │   │       │   ├── PlaylistOverview.stories.tsx
│       │   │   │       │   ├── PlaylistOverview.tsx
│       │   │   │       │   └── index.ts
│       │   │   │       └── index.ts
│       │   │   ├── tags/
│       │   │   │   ├── api/
│       │   │   │   │   ├── index.ts
│       │   │   │   │   └── tags-api.ts
│       │   │   │   ├── index.ts
│       │   │   │   └── ui/
│       │   │   │       ├── TagsList/
│       │   │   │       │   ├── TagsList.module.css
│       │   │   │       │   ├── TagsList.stories.tsx
│       │   │   │       │   ├── TagsList.tsx
│       │   │   │       │   └── index.ts
│       │   │   │       └── index.ts
│       │   │   └── tracks/
│       │   │       ├── api/
│       │   │       │   ├── index.ts
│       │   │       │   ├── tracksApi.ts
│       │   │       │   └── types.ts
│       │   │       ├── index.ts
│       │   │       └── ui/
│       │   │           ├── TrackCard/
│       │   │           │   ├── TrackCard.module.css
│       │   │           │   ├── TrackCard.stories.tsx
│       │   │           │   ├── TrackCard.tsx
│       │   │           │   └── index.ts
│       │   │           ├── TrackInfoCell/
│       │   │           │   ├── TrackInfoCell.module.css
│       │   │           │   ├── TrackInfoCell.tsx
│       │   │           │   └── index.ts
│       │   │           ├── TrackOverview/
│       │   │           │   ├── TrackOverview.module.css
│       │   │           │   ├── TrackOverview.stories.tsx
│       │   │           │   ├── TrackOverview.tsx
│       │   │           │   └── index.ts
│       │   │           ├── TrackRow/
│       │   │           │   ├── TrackRow.module.css
│       │   │           │   └── TrackRow.tsx
│       │   │           ├── TracksTable/
│       │   │           │   ├── TrackTable.stories.tsx
│       │   │           │   ├── TracksTable.tsx
│       │   │           │   └── index.ts
│       │   │           └── index.ts
│       │   ├── layout/
│       │   │   ├── Header/
│       │   │   │   ├── Header.module.css
│       │   │   │   ├── Header.tsx
│       │   │   │   └── index.ts
│       │   │   ├── Layout.module.css
│       │   │   ├── Layout.tsx
│       │   │   ├── Sidebar/
│       │   │   │   ├── MenuLinks/
│       │   │   │   │   ├── MenuLinks.module.css
│       │   │   │   │   ├── MenuLinks.tsx
│       │   │   │   │   └── index.ts
│       │   │   │   ├── Sidebar.module.css
│       │   │   │   ├── Sidebar.tsx
│       │   │   │   └── index.ts
│       │   │   └── index.ts
│       │   ├── main.tsx
│       │   ├── pages/
│       │   │   ├── MainPage/
│       │   │   │   ├── MainPage.module.css
│       │   │   │   ├── MainPage.tsx
│       │   │   │   └── index.ts
│       │   │   ├── PlaylistPage/
│       │   │   │   ├── PlaylistPage.module.css
│       │   │   │   ├── PlaylistPage.tsx
│       │   │   │   ├── index.ts
│       │   │   │   └── ui/
│       │   │   │       └── ControlPanel/
│       │   │   │           ├── ControlPanel.module.css
│       │   │   │           ├── ControlPanel.tsx
│       │   │   │           └── index.ts
│       │   │   ├── PlaylistsPage/
│       │   │   │   ├── PlaylistsPage.module.css
│       │   │   │   ├── PlaylistsPage.tsx
│       │   │   │   └── index.ts
│       │   │   ├── TrackPage/
│       │   │   │   ├── TrackPage.module.css
│       │   │   │   ├── TrackPage.tsx
│       │   │   │   ├── index.ts
│       │   │   │   └── ui/
│       │   │   │       └── ControlPanel/
│       │   │   │           ├── ControlPanel.module.css
│       │   │   │           ├── ControlPanel.tsx
│       │   │   │           └── index.ts
│       │   │   ├── TracksPage/
│       │   │   │   ├── TracksPage.module.css
│       │   │   │   ├── TracksPage.tsx
│       │   │   │   └── index.ts
│       │   │   ├── UserPage/
│       │   │   │   ├── UserPage.module.css
│       │   │   │   ├── UserPage.tsx
│       │   │   │   ├── index.ts
│       │   │   │   └── ui/
│       │   │   │       ├── UserInfo/
│       │   │   │       │   ├── UserInfo.module.css
│       │   │   │       │   ├── UserInfo.tsx
│       │   │   │       │   └── index.ts
│       │   │   │       ├── UserTabs/
│       │   │   │       │   ├── LikedTracksTab/
│       │   │   │       │   │   ├── LikedTracksTab.module.css
│       │   │   │       │   │   ├── LikedTracksTab.tsx
│       │   │   │       │   │   └── index.ts
│       │   │   │       │   ├── MyLikedPlaylistsTab/
│       │   │   │       │   │   ├── MyLikedPlaylistsTab.tsx
│       │   │   │       │   │   └── index.ts
│       │   │   │       │   ├── PlaylistsTab/
│       │   │   │       │   │   ├── PlaylistsTab.module.css
│       │   │   │       │   │   ├── PlaylistsTab.tsx
│       │   │   │       │   │   └── index.ts
│       │   │   │       │   ├── TracksTab/
│       │   │   │       │   │   ├── TracksTab.module.css
│       │   │   │       │   │   ├── TracksTab.tsx
│       │   │   │       │   │   └── index.ts
│       │   │   │       │   ├── UserTabs.tsx
│       │   │   │       │   └── index.ts
│       │   │   │       └── index.ts
│       │   │   ├── common/
│       │   │   │   ├── ContentList/
│       │   │   │   │   ├── ContentList.module.css
│       │   │   │   │   ├── ContentList.tsx
│       │   │   │   │   └── index.ts
│       │   │   │   ├── PageWrapper/
│       │   │   │   │   ├── PageWrapper.module.css
│       │   │   │   │   ├── PageWrapper.tsx
│       │   │   │   │   └── index.ts
│       │   │   │   ├── SearchTextField/
│       │   │   │   │   ├── SearchTextField.tsx
│       │   │   │   │   └── index.ts
│       │   │   │   ├── SortSelect/
│       │   │   │   │   ├── SortSelect.module.css
│       │   │   │   │   ├── SortSelect.tsx
│       │   │   │   │   └── index.ts
│       │   │   │   └── index.ts
│       │   │   └── index.ts
│       │   ├── shared/
│       │   │   ├── components/
│       │   │   │   ├── AudioPlayer/
│       │   │   │   │   ├── AudioPlayer.module.css
│       │   │   │   │   ├── AudioPlayer.stories.tsx
│       │   │   │   │   ├── AudioPlayer.tsx
│       │   │   │   │   └── index.ts
│       │   │   │   ├── Autocomplete/
│       │   │   │   │   ├── Autocomplete.module.css
│       │   │   │   │   ├── Autocomplete.stories.tsx
│       │   │   │   │   ├── Autocomplete.tsx
│       │   │   │   │   └── index.ts
│       │   │   │   ├── Button/
│       │   │   │   │   ├── Button.module.css
│       │   │   │   │   ├── Button.stories.tsx
│       │   │   │   │   ├── Button.tsx
│       │   │   │   │   └── index.ts
│       │   │   │   ├── Card/
│       │   │   │   │   ├── Card.module.css
│       │   │   │   │   ├── Card.stories.tsx
│       │   │   │   │   ├── Card.tsx
│       │   │   │   │   └── index.ts
│       │   │   │   ├── Dialog/
│       │   │   │   │   ├── Dialog.module.css
│       │   │   │   │   ├── Dialog.stories.tsx
│       │   │   │   │   ├── Dialog.tsx
│       │   │   │   │   └── index.ts
│       │   │   │   ├── DropdownMenu/
│       │   │   │   │   ├── DropdownMenu.module.css
│       │   │   │   │   ├── DropdownMenu.stories.tsx
│       │   │   │   │   ├── DropdownMenu.tsx
│       │   │   │   │   └── index.ts
│       │   │   │   ├── Hashtag/
│       │   │   │   │   ├── Tag.module.css
│       │   │   │   │   ├── Tag.stories.tsx
│       │   │   │   │   ├── Tag.tsx
│       │   │   │   │   └── index.ts
│       │   │   │   ├── IconButton/
│       │   │   │   │   ├── IconButton.module.css
│       │   │   │   │   ├── IconButton.stories.tsx
│       │   │   │   │   ├── IconButton.tsx
│       │   │   │   │   └── index.ts
│       │   │   │   ├── ImageUploader/
│       │   │   │   │   ├── ImageUploader.module.css
│       │   │   │   │   ├── ImageUploader.stories.tsx
│       │   │   │   │   ├── ImageUploader.tsx
│       │   │   │   │   └── index.ts
│       │   │   │   ├── Pagination/
│       │   │   │   │   ├── Pagination.module.css
│       │   │   │   │   ├── Pagination.stories.tsx
│       │   │   │   │   ├── Pagination.tsx
│       │   │   │   │   └── index.ts
│       │   │   │   ├── Progress/
│       │   │   │   │   ├── Progress.module.css
│       │   │   │   │   ├── Progress.stories.tsx
│       │   │   │   │   ├── Progress.tsx
│       │   │   │   │   └── index.ts
│       │   │   │   ├── ReactionButtons/
│       │   │   │   │   ├── ReactionButtons.module.css
│       │   │   │   │   ├── ReactionButtons.stories.tsx
│       │   │   │   │   ├── ReactionButtons.tsx
│       │   │   │   │   └── index.ts
│       │   │   │   ├── SearchField/
│       │   │   │   │   ├── SearchField.module.css
│       │   │   │   │   ├── SearchField.stories.tsx
│       │   │   │   │   ├── SearchField.tsx
│       │   │   │   │   └── index.ts
│       │   │   │   ├── Select/
│       │   │   │   │   ├── Select.module.css
│       │   │   │   │   ├── Select.stories.tsx
│       │   │   │   │   ├── Select.tsx
│       │   │   │   │   └── index.ts
│       │   │   │   ├── SortSelect/
│       │   │   │   │   └── Select.tsx
│       │   │   │   ├── Table/
│       │   │   │   │   ├── Table.module.css
│       │   │   │   │   ├── Table.stories.tsx
│       │   │   │   │   ├── Table.tsx
│       │   │   │   │   └── index.ts
│       │   │   │   ├── Tabs/
│       │   │   │   │   ├── Tabs.module.css
│       │   │   │   │   ├── Tabs.stories.tsx
│       │   │   │   │   ├── Tabs.tsx
│       │   │   │   │   └── index.ts
│       │   │   │   ├── TagEditor/
│       │   │   │   │   ├── TagEditor.module.css
│       │   │   │   │   ├── TagEditor.stories.tsx
│       │   │   │   │   ├── TagEditor.tsx
│       │   │   │   │   └── index.ts
│       │   │   │   ├── TextField/
│       │   │   │   │   ├── TextField.module.css
│       │   │   │   │   ├── TextField.stories.tsx
│       │   │   │   │   ├── TextField.tsx
│       │   │   │   │   └── index.ts
│       │   │   │   ├── Textarea/
│       │   │   │   │   ├── Textarea.module.css
│       │   │   │   │   ├── Textarea.stories.tsx
│       │   │   │   │   ├── Textarea.tsx
│       │   │   │   │   └── index.ts
│       │   │   │   ├── Typography/
│       │   │   │   │   ├── Typography.module.css
│       │   │   │   │   ├── Typography.stories.tsx
│       │   │   │   │   ├── Typography.tsx
│       │   │   │   │   └── index.ts
│       │   │   │   └── index.ts
│       │   │   ├── hooks/
│       │   │   │   ├── index.ts
│       │   │   │   └── useGetId.ts
│       │   │   └── icons/
│       │   │       ├── AddToPlaylistIcon.tsx
│       │   │       ├── ArrowDownIcon.tsx
│       │   │       ├── ClockIcon.tsx
│       │   │       ├── CreateIcon.tsx
│       │   │       ├── DeleteIcon.tsx
│       │   │       ├── DislikeIcon.tsx
│       │   │       ├── DownloadIcon.tsx
│       │   │       ├── EditIcon.tsx
│       │   │       ├── HomeIcon.tsx
│       │   │       ├── ImageUploadIcon.tsx
│       │   │       ├── KeyboardArrowLeftIcon.tsx
│       │   │       ├── KeyboardArrowRightIcon.tsx
│       │   │       ├── LibraryIcon.tsx
│       │   │       ├── LikeIcon.tsx
│       │   │       ├── LikeIconFill.tsx
│       │   │       ├── LikeInSquareIcon.tsx
│       │   │       ├── LiveWaveIcon/
│       │   │       │   ├── LiveWaveIcon.module.css
│       │   │       │   ├── LiveWaveIcon.tsx
│       │   │       │   └── index.ts
│       │   │       ├── LogoutIcon.tsx
│       │   │       ├── MoreIcon.tsx
│       │   │       ├── PauseIcon.tsx
│       │   │       ├── PlayIcon.tsx
│       │   │       ├── PlaylistIcon.tsx
│       │   │       ├── PlusIcon.tsx
│       │   │       ├── ProfileIcon.tsx
│       │   │       ├── RepeatIcon.tsx
│       │   │       ├── SearchIcon.tsx
│       │   │       ├── ShuffleIcon.tsx
│       │   │       ├── SkipNextIcon.tsx
│       │   │       ├── SkipPreviousIcon.tsx
│       │   │       ├── TextIcon.tsx
│       │   │       ├── TrackIcon.tsx
│       │   │       ├── UploadIcon.tsx
│       │   │       ├── VolumeIcon.tsx
│       │   │       ├── VolumeMuteIcon.tsx
│       │   │       └── index.ts
│       │   ├── styles/
│       │   │   ├── fonts.css
│       │   │   ├── global.css
│       │   │   ├── reset.css
│       │   │   └── variables.css
│       │   ├── vite-env.d.ts
│       │   └── widgets/
│       │       └── Player/
│       │           ├── Player.module.css
│       │           ├── Player.tsx
│       │           └── index.ts
│       ├── stylelint.config.js
│       ├── tsconfig.app.json
│       ├── tsconfig.json
│       ├── tsconfig.node.json
│       └── vite.config.ts
├── architecture/
│   └── microfrontends/
│       ├── player/
│       │   ├── .gitignore
│       │   ├── README.md
│       │   ├── eslint.config.js
│       │   ├── index.html
│       │   ├── package.json
│       │   ├── src/
│       │   │   ├── App.css
│       │   │   ├── App.tsx
│       │   │   ├── index.css
│       │   │   └── main.tsx
│       │   ├── tsconfig.app.json
│       │   ├── tsconfig.json
│       │   ├── tsconfig.node.json
│       │   ├── vite.config.readme.md
│       │   └── vite.config.ts
│       └── root/
│           ├── .gitignore
│           ├── README.md
│           ├── eslint.config.js
│           ├── index.html
│           ├── package.json
│           ├── src/
│           │   ├── App.css
│           │   ├── App.tsx
│           │   ├── index.css
│           │   └── main.tsx
│           ├── tsconfig.app.json
│           ├── tsconfig.json
│           ├── tsconfig.node.json
│           └── vite.config.ts
├── content-thoughts/
│   └── search-input/
│       └── info.md
├── docs/
│   ├── feature-comparison.md
│   └── todos-features.md
├── eslint.config.js
├── experiment-apps/
│   ├── musicfun-tanstack-query-orval-small-example/
│   │   ├── .gitignore
│   │   ├── README.md
│   │   ├── eslint.config.js
│   │   ├── index.html
│   │   ├── orval.config.cjs
│   │   ├── package.json
│   │   ├── src/
│   │   │   ├── app/
│   │   │   │   ├── entrypoint/
│   │   │   │   │   └── main.tsx
│   │   │   │   ├── layouts/
│   │   │   │   │   ├── root-layout.module.css
│   │   │   │   │   └── root-layout.tsx
│   │   │   │   ├── providers/
│   │   │   │   │   └── web-socket-provider.tsx
│   │   │   │   ├── query-client/
│   │   │   │   │   └── query-client.tsx
│   │   │   │   ├── routes/
│   │   │   │   │   ├── __root.tsx
│   │   │   │   │   ├── index.tsx
│   │   │   │   │   ├── my-playlists.tsx
│   │   │   │   │   ├── oauth/
│   │   │   │   │   │   └── callback.tsx
│   │   │   │   │   └── playlists-with-filters.tsx
│   │   │   │   └── styles/
│   │   │   │       ├── index.css
│   │   │   │       └── reset.css
│   │   │   ├── features/
│   │   │   │   ├── auth/
│   │   │   │   │   ├── api/
│   │   │   │   │   │   ├── auth-api.types.ts
│   │   │   │   │   │   ├── use-login.mutation.ts
│   │   │   │   │   │   ├── use-logout.mutation.ts
│   │   │   │   │   │   └── use-me.query.ts
│   │   │   │   │   ├── index.tsx
│   │   │   │   │   └── ui/
│   │   │   │   │       ├── account-bar.module.css
│   │   │   │   │       ├── account-bar.tsx
│   │   │   │   │       ├── current-user/
│   │   │   │   │       │   └── current-user.tsx
│   │   │   │   │       ├── login-button/
│   │   │   │   │       │   ├── login-button.tsx
│   │   │   │   │       │   └── use-login.tsx
│   │   │   │   │       └── logout-button/
│   │   │   │   │           ├── logout-button.tsx
│   │   │   │   │           └── use-logout.ts
│   │   │   │   └── playlists/
│   │   │   │       ├── add-playlist-form/
│   │   │   │       │   ├── add-playlist-form.module.css
│   │   │   │       │   └── add-playlist-form.tsx
│   │   │   │       ├── api/
│   │   │   │       │   └── use-playlists-query.tsx
│   │   │   │       ├── edit-playlist-form/
│   │   │   │       │   └── edit-playlist-form.tsx
│   │   │   │       ├── list/
│   │   │   │       │   ├── paginated-playlists.module.css
│   │   │   │       │   ├── paginated-playlists.tsx
│   │   │   │       │   └── playlists.tsx
│   │   │   │       └── playlist-cover/
│   │   │   │           ├── playlist-cover.module.css
│   │   │   │           └── playlist-cover.tsx
│   │   │   ├── pages/
│   │   │   │   ├── auth/
│   │   │   │   │   ├── index.tsx
│   │   │   │   │   └── ui/
│   │   │   │   │       └── oauth-callback-page.tsx
│   │   │   │   └── playlists/
│   │   │   │       └── ui/
│   │   │   │           ├── my-playlists/
│   │   │   │           │   ├── my-playlists-page.module.css
│   │   │   │           │   └── my-playlists-page.tsx
│   │   │   │           └── playlists-with-filters-page.tsx
│   │   │   ├── shared/
│   │   │   │   ├── api/
│   │   │   │   │   ├── client.ts
│   │   │   │   │   ├── index.ts
│   │   │   │   │   ├── json-api-error.ts
│   │   │   │   │   ├── orval/
│   │   │   │   │   │   ├── artists/
│   │   │   │   │   │   │   └── artists.ts
│   │   │   │   │   │   ├── authentication/
│   │   │   │   │   │   │   └── authentication.ts
│   │   │   │   │   │   ├── custom-instance.ts
│   │   │   │   │   │   ├── musicfun.schemas.ts
│   │   │   │   │   │   ├── musicfun.ts
│   │   │   │   │   │   ├── playlists-owner/
│   │   │   │   │   │   │   └── playlists-owner.ts
│   │   │   │   │   │   ├── playlists-public/
│   │   │   │   │   │   │   └── playlists-public.ts
│   │   │   │   │   │   ├── tags/
│   │   │   │   │   │   │   └── tags.ts
│   │   │   │   │   │   ├── tracks-owner/
│   │   │   │   │   │   │   └── tracks-owner.ts
│   │   │   │   │   │   └── tracks-public/
│   │   │   │   │   │       └── tracks-public.ts
│   │   │   │   │   ├── query-error-handler-for-rhf-factory.ts
│   │   │   │   │   ├── request-wrapper.ts
│   │   │   │   │   ├── schema.ts
│   │   │   │   │   └── socket.ts
│   │   │   │   ├── config/
│   │   │   │   │   └── api.config.ts
│   │   │   │   ├── db/
│   │   │   │   │   └── localstorage-keys.ts
│   │   │   │   ├── routes/
│   │   │   │   │   └── routes.ts
│   │   │   │   └── ui/
│   │   │   │       ├── header/
│   │   │   │       │   ├── header.component.tsx
│   │   │   │       │   └── header.module.css
│   │   │   │       └── pagination/
│   │   │   │           ├── pagination-nav/
│   │   │   │           │   ├── pagination-nav.module.css
│   │   │   │           │   └── pagination-nav.tsx
│   │   │   │           ├── pagination.module.css
│   │   │   │           ├── pagination.tsx
│   │   │   │           └── utils/
│   │   │   │               └── get-pagination-pages.ts
│   │   │   └── vite-env.d.ts
│   │   ├── tsconfig.app.json
│   │   ├── tsconfig.json
│   │   ├── tsconfig.node.json
│   │   ├── tsr.config.json
│   │   └── vite.config.ts
│   ├── musicfun-tanstack-query-small-example/
│   │   ├── .gitignore
│   │   ├── README.md
│   │   ├── eslint.config.js
│   │   ├── index.html
│   │   ├── package.json
│   │   ├── src/
│   │   │   ├── app/
│   │   │   │   ├── entrypoint/
│   │   │   │   │   └── main.tsx
│   │   │   │   ├── layouts/
│   │   │   │   │   ├── root-layout.module.css
│   │   │   │   │   └── root-layout.tsx
│   │   │   │   ├── providers/
│   │   │   │   │   └── web-socket-provider.tsx
│   │   │   │   ├── query-client/
│   │   │   │   │   └── query-client.tsx
│   │   │   │   ├── routes/
│   │   │   │   │   ├── __root.tsx
│   │   │   │   │   ├── index.tsx
│   │   │   │   │   ├── my-playlists.tsx
│   │   │   │   │   ├── oauth/
│   │   │   │   │   │   └── callback.tsx
│   │   │   │   │   └── playlists-with-filters.tsx
│   │   │   │   └── styles/
│   │   │   │       ├── index.css
│   │   │   │       └── reset.css
│   │   │   ├── features/
│   │   │   │   ├── auth/
│   │   │   │   │   ├── api/
│   │   │   │   │   │   ├── auth-api.types.ts
│   │   │   │   │   │   ├── use-login.mutation.ts
│   │   │   │   │   │   ├── use-logout.mutation.ts
│   │   │   │   │   │   └── use-me.query.ts
│   │   │   │   │   ├── index.tsx
│   │   │   │   │   └── ui/
│   │   │   │   │       ├── account-bar.module.css
│   │   │   │   │       ├── account-bar.tsx
│   │   │   │   │       ├── current-user/
│   │   │   │   │       │   └── current-user.tsx
│   │   │   │   │       ├── login-button/
│   │   │   │   │       │   ├── login-button.tsx
│   │   │   │   │       │   └── use-login.tsx
│   │   │   │   │       └── logout-button/
│   │   │   │   │           ├── logout-button.tsx
│   │   │   │   │           └── use-logout.ts
│   │   │   │   └── playlists/
│   │   │   │       ├── add-playlist-form/
│   │   │   │       │   ├── add-playlist-form.module.css
│   │   │   │       │   └── add-playlist-form.tsx
│   │   │   │       ├── api/
│   │   │   │       │   └── use-playlists-query.tsx
│   │   │   │       ├── edit-playlist-form/
│   │   │   │       │   └── edit-playlist-form.tsx
│   │   │   │       ├── list/
│   │   │   │       │   ├── paginated-playlists.module.css
│   │   │   │       │   ├── paginated-playlists.tsx
│   │   │   │       │   └── playlists.tsx
│   │   │   │       └── playlist-cover/
│   │   │   │           ├── playlist-cover.module.css
│   │   │   │           └── playlist-cover.tsx
│   │   │   ├── pages/
│   │   │   │   ├── auth/
│   │   │   │   │   ├── index.tsx
│   │   │   │   │   └── ui/
│   │   │   │   │       └── oauth-callback-page.tsx
│   │   │   │   └── playlists/
│   │   │   │       └── ui/
│   │   │   │           ├── my-playlists/
│   │   │   │           │   ├── my-playlists-page.module.css
│   │   │   │           │   └── my-playlists-page.tsx
│   │   │   │           └── playlists-with-filters-page.tsx
│   │   │   ├── shared/
│   │   │   │   ├── api/
│   │   │   │   │   ├── client.ts
│   │   │   │   │   ├── index.ts
│   │   │   │   │   ├── json-api-error.ts
│   │   │   │   │   ├── query-error-handler-for-rhf-factory.ts
│   │   │   │   │   ├── request-wrapper.ts
│   │   │   │   │   ├── schema.ts
│   │   │   │   │   └── socket.ts
│   │   │   │   ├── config/
│   │   │   │   │   └── api.config.ts
│   │   │   │   ├── db/
│   │   │   │   │   └── localstorage-keys.ts
│   │   │   │   ├── routes/
│   │   │   │   │   └── routes.ts
│   │   │   │   └── ui/
│   │   │   │       ├── header/
│   │   │   │       │   ├── header.component.tsx
│   │   │   │       │   └── header.module.css
│   │   │   │       └── pagination/
│   │   │   │           ├── pagination-nav/
│   │   │   │           │   ├── pagination-nav.module.css
│   │   │   │           │   └── pagination-nav.tsx
│   │   │   │           ├── pagination.module.css
│   │   │   │           ├── pagination.tsx
│   │   │   │           └── utils/
│   │   │   │               └── get-pagination-pages.ts
│   │   │   └── vite-env.d.ts
│   │   ├── tsconfig.app.json
│   │   ├── tsconfig.json
│   │   ├── tsconfig.node.json
│   │   ├── tsr.config.json
│   │   └── vite.config.ts
│   └── trelly-rtk/
│       ├── .gitignore
│       ├── .prettierrc
│       ├── README.md
│       ├── index.html
│       ├── openapi-config.js
│       ├── package.json
│       ├── src/
│       │   ├── app/
│       │   │   ├── api/
│       │   │   │   ├── baseApi.ts
│       │   │   │   ├── baseQuery.ts
│       │   │   │   └── baseQueryWithReauth.ts
│       │   │   ├── model/
│       │   │   │   ├── app-slice.ts
│       │   │   │   └── store.ts
│       │   │   └── ui/
│       │   │       ├── App.module.css
│       │   │       ├── App.tsx
│       │   │       └── Main.tsx
│       │   ├── common/
│       │   │   ├── actions/
│       │   │   │   ├── actions.ts
│       │   │   │   └── index.ts
│       │   │   ├── components/
│       │   │   │   ├── CreateItemForm/
│       │   │   │   │   └── CreateItemForm.tsx
│       │   │   │   ├── EditableSpan/
│       │   │   │   │   └── EditableSpan.tsx
│       │   │   │   ├── ErrorSnackbar/
│       │   │   │   │   └── ErrorSnackbar.tsx
│       │   │   │   ├── Header/
│       │   │   │   │   └── Header.tsx
│       │   │   │   ├── NavButton/
│       │   │   │   │   └── NavButton.ts
│       │   │   │   ├── PageNotFound/
│       │   │   │   │   ├── PageNotFound.module.css
│       │   │   │   │   └── PageNotFound.tsx
│       │   │   │   ├── ProtectedRoute/
│       │   │   │   │   └── ProtectedRoute.tsx
│       │   │   │   └── index.ts
│       │   │   ├── constants/
│       │   │   │   ├── constants.ts
│       │   │   │   └── index.ts
│       │   │   ├── enums/
│       │   │   │   ├── enums.ts
│       │   │   │   └── index.ts
│       │   │   ├── hooks/
│       │   │   │   ├── index.ts
│       │   │   │   ├── useAppDispatch.ts
│       │   │   │   └── useAppSelector.ts
│       │   │   ├── instance/
│       │   │   │   ├── index.ts
│       │   │   │   └── instance.ts
│       │   │   ├── routing/
│       │   │   │   ├── Routing.tsx
│       │   │   │   └── index.ts
│       │   │   ├── styles/
│       │   │   │   ├── container.styles.ts
│       │   │   │   └── index.ts
│       │   │   ├── theme/
│       │   │   │   ├── index.ts
│       │   │   │   └── theme.ts
│       │   │   ├── types/
│       │   │   │   ├── index.ts
│       │   │   │   └── types.ts
│       │   │   └── utils/
│       │   │       ├── createAppSlice.ts
│       │   │       ├── handleError.ts
│       │   │       ├── index.ts
│       │   │       ├── isErrorWithMessage.ts
│       │   │       └── isTokens.ts
│       │   ├── features/
│       │   │   ├── auth/
│       │   │   │   ├── api/
│       │   │   │   │   ├── authApi.ts
│       │   │   │   │   └── authApi.types.ts
│       │   │   │   ├── lib/
│       │   │   │   │   └── schemas/
│       │   │   │   │       ├── index.ts
│       │   │   │   │       └── loginSchema.ts
│       │   │   │   └── ui/
│       │   │   │       ├── Login/
│       │   │   │       │   ├── Login.module.css
│       │   │   │       │   └── Login.tsx
│       │   │   │       ├── OAuthCallback/
│       │   │   │       │   └── OAuthCallback.tsx
│       │   │   │       └── UserBlock/
│       │   │   │           └── UserBlock.tsx
│       │   │   ├── boards/
│       │   │   │   ├── api/
│       │   │   │   │   ├── boardsApi.ts
│       │   │   │   │   └── boardsApi.types.ts
│       │   │   │   ├── lib/
│       │   │   │   │   └── utils/
│       │   │   │   │       ├── createTaskModel.ts
│       │   │   │   │       └── index.ts
│       │   │   │   └── ui/
│       │   │   │       └── Boards/
│       │   │   │           ├── BoardItem/
│       │   │   │           │   ├── BoardItem.tsx
│       │   │   │           │   ├── BoardTitle/
│       │   │   │           │   │   ├── BoardTitle.module.css
│       │   │   │           │   │   └── BoardTitle.tsx
│       │   │   │           │   └── FilterButtons/
│       │   │   │           │       └── FilterButtons.tsx
│       │   │   │           ├── BoardSkeleton/
│       │   │   │           │   ├── BoardSkeleton.module.css
│       │   │   │           │   └── BoardSkeleton.tsx
│       │   │   │           └── Boards.tsx
│       │   │   └── tasks/
│       │   │       ├── api/
│       │   │       │   ├── tasksApi.ts
│       │   │       │   └── tasksApi.types.ts
│       │   │       └── ui/
│       │   │           └── Tasks/
│       │   │               ├── TaskItem/
│       │   │               │   ├── TaskItem.styles.ts
│       │   │               │   └── TaskItem.tsx
│       │   │               ├── Tasks.tsx
│       │   │               ├── TasksPagination/
│       │   │               │   ├── TasksPagination.module.css
│       │   │               │   └── TasksPagination.tsx
│       │   │               └── TasksSkeleton/
│       │   │                   └── TasksSkeleton.tsx
│       │   ├── index.css
│       │   ├── main.tsx
│       │   └── vite-env.d.ts
│       ├── tsconfig.app.json
│       ├── tsconfig.json
│       ├── tsconfig.node.json
│       └── vite.config.ts
├── package.json
├── packages/
│   └── musicfun-api-sdk/
│       ├── package.json
│       ├── src/
│       │   ├── api/
│       │   │   ├── artists/
│       │   │   │   ├── artistsApi.ts
│       │   │   │   └── artistsApi.types.ts
│       │   │   ├── auth/
│       │   │   │   ├── authApi.ts
│       │   │   │   └── authApi.types.ts
│       │   │   ├── playlists/
│       │   │   │   ├── playlistsApi.ts
│       │   │   │   └── playlistsApi.types.ts
│       │   │   ├── tags/
│       │   │   │   ├── tagsApi.ts
│       │   │   │   └── tagsApi.types.ts
│       │   │   └── tracks/
│       │   │       ├── tracksApi.ts
│       │   │       └── tracksApi.types.ts
│       │   ├── common/
│       │   │   ├── apiEntities/
│       │   │   │   └── apiEntities.ts
│       │   │   ├── instance/
│       │   │   │   └── instance.ts
│       │   │   ├── types/
│       │   │   │   ├── common.types.ts
│       │   │   │   ├── enums.ts
│       │   │   │   └── playlists-tracks.types.ts
│       │   │   └── utils/
│       │   │       └── urlHelper.ts
│       │   ├── index.ts
│       │   └── v2/
│       │       └── request.ts
│       └── tsconfig.json
├── public/
│   ├── 404.html
│   └── index.html
├── type-comparison-examples.md
└── youtube/
    ├── markup/
    │   ├── .gitignore
    │   ├── README.md
    │   ├── eslint.config.js
    │   ├── index.html
    │   ├── package.json
    │   ├── tsconfig.app.json
    │   ├── tsconfig.json
    │   ├── tsconfig.node.json
    │   └── vite.config.ts
    ├── rtk-query/
    │   └── lesson1/
    │       ├── .gitignore
    │       ├── .prettierrc
    │       ├── AGENTS.md
    │       ├── README.md
    │       ├── eslint.config.js
    │       ├── index.html
    │       ├── package.json
    │       ├── src/
    │       │   ├── app/
    │       │   │   ├── api/
    │       │   │   │   ├── baseApi.ts
    │       │   │   │   ├── baseQuery.ts
    │       │   │   │   └── baseQueryWithReauth.ts
    │       │   │   ├── model/
    │       │   │   │   └── store.ts
    │       │   │   └── ui/
    │       │   │       ├── App/
    │       │   │       │   ├── App.module.css
    │       │   │       │   └── App.tsx
    │       │   │       └── MainPage/
    │       │   │           └── MainPage.tsx
    │       │   ├── common/
    │       │   │   ├── components/
    │       │   │   │   ├── Header/
    │       │   │   │   │   ├── Header.module.css
    │       │   │   │   │   └── Header.tsx
    │       │   │   │   ├── LinearProgress/
    │       │   │   │   │   ├── LinearProgress.module.css
    │       │   │   │   │   └── LinearProgress.tsx
    │       │   │   │   ├── PageNotFound/
    │       │   │   │   │   ├── PageNotFound.module.css
    │       │   │   │   │   └── PageNotFound.tsx
    │       │   │   │   ├── Pagination/
    │       │   │   │   │   ├── Pagination.module.css
    │       │   │   │   │   └── Pagination.tsx
    │       │   │   │   └── index.tsx
    │       │   │   ├── constants/
    │       │   │   │   ├── constants.ts
    │       │   │   │   └── index.ts
    │       │   │   ├── enums/
    │       │   │   │   ├── enums.ts
    │       │   │   │   └── index.ts
    │       │   │   ├── hooks/
    │       │   │   │   ├── index.ts
    │       │   │   │   ├── useDebounceValue.ts
    │       │   │   │   ├── useGlobalLoading.ts
    │       │   │   │   └── useInfiniteScroll.ts
    │       │   │   ├── routing/
    │       │   │   │   ├── Routing.tsx
    │       │   │   │   └── index.ts
    │       │   │   ├── schemas/
    │       │   │   │   ├── index.ts
    │       │   │   │   └── schemas.ts
    │       │   │   ├── socket/
    │       │   │   │   ├── getSocket.ts
    │       │   │   │   ├── index.ts
    │       │   │   │   └── subscribeToEvent.ts
    │       │   │   ├── types/
    │       │   │   │   ├── index.ts
    │       │   │   │   └── types.ts
    │       │   │   └── utils/
    │       │   │       ├── errorToast.ts
    │       │   │       ├── getPaginationPages.ts
    │       │   │       ├── handleErrors.ts
    │       │   │       ├── index.ts
    │       │   │       ├── isErrorWithDetailArray.ts
    │       │   │       ├── isErrorWithProperty.ts
    │       │   │       ├── isTokens.ts
    │       │   │       ├── trimToMaxLength.ts
    │       │   │       └── withZodCatch.ts
    │       │   ├── features/
    │       │   │   ├── auth/
    │       │   │   │   ├── api/
    │       │   │   │   │   ├── authApi.ts
    │       │   │   │   │   └── authApi.types.ts
    │       │   │   │   ├── model/
    │       │   │   │   │   └── auth.schemas.ts
    │       │   │   │   └── ui/
    │       │   │   │       ├── Login/
    │       │   │   │       │   └── Login.tsx
    │       │   │   │       ├── OAuthCallback/
    │       │   │   │       │   └── OAuthCallback.tsx
    │       │   │   │       └── ProfilePage/
    │       │   │   │           ├── ProfilePage.module.css
    │       │   │   │           └── ProfilePage.tsx
    │       │   │   ├── playlists/
    │       │   │   │   ├── api/
    │       │   │   │   │   ├── playlistsApi.ts
    │       │   │   │   │   └── playlistsApi.types.ts
    │       │   │   │   ├── model/
    │       │   │   │   │   └── playlists.schemas.ts
    │       │   │   │   └── ui/
    │       │   │   │       ├── CreatePlaylistForm/
    │       │   │   │       │   ├── CreatePlaylistForm.module.css
    │       │   │   │       │   └── CreatePlaylistForm.tsx
    │       │   │   │       ├── EditPlaylistForm/
    │       │   │   │       │   └── EditPlaylistForm.tsx
    │       │   │   │       ├── PlaylistItem/
    │       │   │   │       │   ├── PlaylistCover/
    │       │   │   │       │   │   ├── PlaylistCover.module.css
    │       │   │   │       │   │   └── PlaylistCover.tsx
    │       │   │   │       │   ├── PlaylistDescription/
    │       │   │   │       │   │   └── PlaylistDescription.tsx
    │       │   │   │       │   └── PlaylistItem.tsx
    │       │   │   │       ├── PlaylistsList/
    │       │   │   │       │   ├── PlaylistsList.module.css
    │       │   │   │       │   └── PlaylistsList.tsx
    │       │   │   │       ├── PlaylistsPage.module.css
    │       │   │   │       └── PlaylistsPage.tsx
    │       │   │   └── tracks/
    │       │   │       ├── api/
    │       │   │       │   ├── tracksApi.ts
    │       │   │       │   └── tracksApi.types.ts
    │       │   │       ├── model/
    │       │   │       │   └── tracks.schemas.ts
    │       │   │       └── ui/
    │       │   │           ├── LoadingTrigger/
    │       │   │           │   └── LoadingTrigger.tsx
    │       │   │           ├── TracksList/
    │       │   │           │   ├── TracksList.module.css
    │       │   │           │   └── TracksList.tsx
    │       │   │           └── TracksPage.tsx
    │       │   ├── index.css
    │       │   ├── main.tsx
    │       │   └── vite-env.d.ts
    │       ├── tsconfig.app.json
    │       ├── tsconfig.json
    │       ├── tsconfig.node.json
    │       └── vite.config.ts
    └── tanstack-query-router-fsd/
        └── lesson1/
            ├── .gitignore
            ├── README.md
            ├── eslint.config.js
            ├── index.html
            ├── package.json
            ├── src/
            │   ├── app/
            │   │   ├── entrypoint/
            │   │   │   └── main.tsx
            │   │   ├── layouts/
            │   │   │   ├── root-layout.module.css
            │   │   │   └── root-layout.tsx
            │   │   ├── routes/
            │   │   │   ├── __root.tsx
            │   │   │   ├── index.tsx
            │   │   │   ├── my-playlists.tsx
            │   │   │   ├── oauth/
            │   │   │   │   └── callback.tsx
            │   │   │   └── routeTree.gen.ts
            │   │   ├── styles/
            │   │   │   ├── index.css
            │   │   │   └── reset.css
            │   │   ├── tanstack-query/
            │   │   │   └── query-client-instance.tsx
            │   │   └── tanstack-router/
            │   │       └── router-instance.tsx
            │   ├── features/
            │   │   ├── auth/
            │   │   │   ├── api/
            │   │   │   │   ├── use-login-mutation.tsx
            │   │   │   │   ├── use-logout-mutation.tsx
            │   │   │   │   └── use-me-query.ts
            │   │   │   └── ui/
            │   │   │       ├── account-bar.module.css
            │   │   │       ├── account-bar.tsx
            │   │   │       ├── current-user/
            │   │   │       │   └── current-user.tsx
            │   │   │       ├── login-button.tsx
            │   │   │       └── logout-button.tsx
            │   │   └── playlists/
            │   │       ├── add-playlist/
            │   │       │   ├── api/
            │   │       │   │   └── use-add-playlist-mutation.ts
            │   │       │   └── ui/
            │   │       │       └── add-playlist-form.tsx
            │   │       ├── delete-playlist/
            │   │       │   ├── api/
            │   │       │   │   └── use-delete-mutation.ts
            │   │       │   └── ui/
            │   │       │       └── delete-playlist.tsx
            │   │       └── edit-playlist/
            │   │           ├── api/
            │   │           │   ├── use-playlist-query.tsx
            │   │           │   └── use-update-playlist-mutation.ts
            │   │           └── ui/
            │   │               └── edit-playlist-form.tsx
            │   ├── pages/
            │   │   ├── auth/
            │   │   │   └── oauth-callback-page.tsx
            │   │   ├── my-playlists-page.tsx
            │   │   └── playlists-page.tsx
            │   ├── shared/
            │   │   ├── api/
            │   │   │   ├── client.ts
            │   │   │   ├── keys-factories/
            │   │   │   │   ├── auth-keys-factory.ts
            │   │   │   │   └── playlists-keys-factory.ts
            │   │   │   └── schema.ts
            │   │   ├── config/
            │   │   │   ├── api-config.ts
            │   │   │   └── localstorage-keys.ts
            │   │   ├── ui/
            │   │   │   ├── header/
            │   │   │   │   ├── header.module.css
            │   │   │   │   └── header.tsx
            │   │   │   ├── pagination/
            │   │   │   │   ├── pagination-nav/
            │   │   │   │   │   ├── pagination-nav.module.css
            │   │   │   │   │   └── pagination-nav.tsx
            │   │   │   │   ├── pagination.module.css
            │   │   │   │   ├── pagination.tsx
            │   │   │   │   └── utils/
            │   │   │   │       └── get-pagination-pages.ts
            │   │   │   └── util/
            │   │   │       └── query-error-handler-for-rhf-factory.ts
            │   │   └── util/
            │   │       └── json-api-error.ts
            │   ├── vite-env.d.ts
            │   └── widgets/
            │       └── playlists/
            │           ├── api/
            │           │   └── use-playlists-query.ts
            │           └── ui/
            │               └── playlists.tsx
            ├── tsconfig.app.json
            ├── tsconfig.json
            ├── tsconfig.node.json
            ├── tsr.config.json
            └── vite.config.ts
Download .txt
Showing preview only (213K chars total). Download the full file or copy to clipboard to get everything.
SYMBOL INDEX (1980 symbols across 630 files)

FILE: apps/nextjs/src/app/actions/auth/logout.action.tsx
  function logout (line 4) | async function logout() {

FILE: apps/nextjs/src/app/api/oauth/callback/route.ts
  function GET (line 8) | async function GET(request: Request) {

FILE: apps/nextjs/src/app/layout.tsx
  function RootLayout (line 21) | function RootLayout({

FILE: apps/nextjs/src/app/page.tsx
  function Home (line 6) | async function Home() {

FILE: apps/nextjs/src/app/profile/page.tsx
  function ProfilePage (line 7) | async function ProfilePage() {

FILE: apps/nextjs/src/app/redirect/page.tsx
  function ProfilePage (line 8) | async function ProfilePage() {

FILE: apps/nextjs/src/middleware.ts
  function middleware (line 5) | async function middleware(request: NextRequest) {

FILE: apps/nextjs/src/reauth-middleware.ts
  function reauthMiddleware (line 18) | async function reauthMiddleware(request: NextRequest) {

FILE: apps/nextjs/src/shared/api/auth-api.ts
  function checkResponse (line 15) | async function checkResponse<T>(response: Response): Promise<T> {
  method login (line 25) | async login(payload: OAuthLoginArgs): Promise<AuthTokensResponse> {
  method logout (line 35) | async logout(payload: RefreshTokensArgs): Promise<void> {
  method oauthUrl (line 49) | oauthUrl(redirectUrl: string): string {
  method refreshToken (line 56) | async refreshToken(payload: RefreshTokensArgs): Promise<AuthTokensRespon...
  method getMe (line 66) | async getMe(): Promise<MeResponseResponse> {

FILE: apps/nextjs/src/shared/api/authApi.types.ts
  type MeResponseResponse (line 1) | type MeResponseResponse = {
  type AuthTokensResponse (line 6) | type AuthTokensResponse = {
  type RefreshTokensArgs (line 11) | type RefreshTokensArgs = {
  type OAuthLoginArgs (line 15) | type OAuthLoginArgs = {

FILE: apps/nextjs/src/shared/api/tracks/tracksApi.ts
  method fetchTracks (line 15) | async fetchTracks({ pageSize = 3, pageNumber, search = '' }: FetchTracks...
  method fetchTracksInPlaylist (line 25) | async fetchTracksInPlaylist({ playlistId }: { playlistId: string }) {
  method fetchTrackById (line 31) | async fetchTrackById(trackId: string) {
  method createTrack (line 37) | async createTrack({ title, file }: { title: string; file: File }) {
  method removeTrack (line 51) | async removeTrack(trackId: string) {
  method updateTrack (line 69) | async updateTrack({ trackId, payload }: { trackId: string; payload: Upda...
  method addTrackToPlaylist (line 79) | async addTrackToPlaylist({ playlistId, trackId }: { playlistId: string; ...
  method removeTrackFromPlaylist (line 88) | async removeTrackFromPlaylist({ playlistId, trackId }: { playlistId: str...
  method reorderTracks (line 93) | async reorderTracks({
  method like (line 110) | async like(trackId: string) {
  method dislike (line 120) | async dislike(trackId: string) {

FILE: apps/nextjs/src/shared/api/tracks/tracksApi.types.ts
  type TrackDetails (line 7) | type TrackDetails<T> = {
  type BaseAttributes (line 14) | type BaseAttributes = {
  type FetchTracksAttributes (line 21) | type FetchTracksAttributes = BaseAttributes & {
  type TrackDetailAttributes (line 25) | type TrackDetailAttributes = BaseAttributes & {
  type PlaylistItemAttributes (line 40) | type PlaylistItemAttributes = BaseAttributes & {
  type TrackAttachment (line 46) | type TrackAttachment = {
  type FetchTracksResponse (line 59) | type FetchTracksResponse = {
  type FetchPlaylistsTracksResponse (line 64) | type FetchPlaylistsTracksResponse = {
  type ReactionResponse (line 69) | type ReactionResponse = {
  type FetchTracksArgs (line 77) | type FetchTracksArgs = {
  type UpdateTrackArgs (line 83) | type UpdateTrackArgs = {
  type TrackVisibility (line 93) | type TrackVisibility = 'private' | 'public'
  type TrackProcessingStatus (line 95) | type TrackProcessingStatus = 'uploaded' | 'converting' | 'ready'

FILE: apps/nextjs/src/shared/common.types.ts
  type Nullable (line 1) | type Nullable<T> = T | null

FILE: apps/nextjs/src/shared/utils/cookieHelpers.ts
  type CookieDef (line 5) | interface CookieDef {
  function createAccessTokenCookie (line 16) | function createAccessTokenCookie(token: string): CookieDef {
  function createRefreshTokenCookie (line 29) | function createRefreshTokenCookie(token: string): CookieDef {

FILE: apps/nextjs/src/shared/utils/jwt-util.ts
  function parseJwtExp (line 7) | function parseJwtExp(token: string): number {
  function getSecondsToExpiration (line 28) | function getSecondsToExpiration(token: string): number {
  function getJwtExpirationMaxAge (line 38) | function getJwtExpirationMaxAge(token: string): number {

FILE: apps/react-effector-fsd/src/app/App.tsx
  function App (line 12) | function App() {

FILE: apps/react-effector-fsd/src/features/auth/model/auth-api.types.ts
  type RefreshOutput (line 4) | type RefreshOutput = components['schemas']['RefreshOutput']
  type RefreshRequestPayload (line 5) | type RefreshRequestPayload = components['schemas']['RefreshRequestPayload']
  type LoginRequestPayload (line 6) | type LoginRequestPayload = components['schemas']['LoginRequestPayload']

FILE: apps/react-effector-fsd/src/features/auth/model/user.types.ts
  type User (line 3) | type User = components['schemas']['GetMeOutput'] | null

FILE: apps/react-effector-fsd/src/features/auth/ui/ProfileDropdownMenu/ProfileDropdownMenu.stories.tsx
  type Story (line 15) | type Story = StoryObj<typeof ProfileDropdownMenu>

FILE: apps/react-effector-fsd/src/pages/home/Home.tsx
  function Home (line 1) | function Home() {

FILE: apps/react-effector-fsd/src/shared/api/client.ts
  function makeRefreshToken (line 28) | function makeRefreshToken(): Promise<string> {
  method onRequest (line 60) | async onRequest({ request }) {
  method onResponse (line 69) | async onResponse({ request, response }) {
  constant LOCAL_HOSTNAMES (line 106) | const LOCAL_HOSTNAMES = new Set(['localhost', '127.0.0.1', '::1', '0.0.0...
  function isLocalClient (line 108) | function isLocalClient(): boolean {
  function assertApiConfig (line 114) | function assertApiConfig() {

FILE: apps/react-effector-fsd/src/shared/api/schema.ts
  type paths (line 6) | interface paths {
  type webhooks (line 557) | type webhooks = Record<string, never>
  type components (line 558) | interface components {
  type SchemaUserRef (line 1142) | type SchemaUserRef = components['schemas']['UserRef']
  type SchemaImageVariant (line 1143) | type SchemaImageVariant = components['schemas']['ImageVariant']
  type SchemaPlaylistImagesOutputDto (line 1144) | type SchemaPlaylistImagesOutputDto = components['schemas']['PlaylistImag...
  type SchemaTagRef (line 1145) | type SchemaTagRef = components['schemas']['TagRef']
  type SchemaPlaylistListItemAttributes (line 1146) | type SchemaPlaylistListItemAttributes = components['schemas']['PlaylistL...
  type SchemaPlaylistListItemResource (line 1147) | type SchemaPlaylistListItemResource = components['schemas']['PlaylistLis...
  type SchemaGetMyPlaylistsOutput (line 1148) | type SchemaGetMyPlaylistsOutput = components['schemas']['GetMyPlaylistsO...
  type SchemaCreatePlaylistRequestPayload (line 1149) | type SchemaCreatePlaylistRequestPayload =
  type SchemaPlaylistAttributes (line 1151) | type SchemaPlaylistAttributes = components['schemas']['PlaylistAttributes']
  type SchemaPlaylistResource (line 1152) | type SchemaPlaylistResource = components['schemas']['PlaylistResource']
  type SchemaGetPlaylistOutput (line 1153) | type SchemaGetPlaylistOutput = components['schemas']['GetPlaylistOutput']
  type SchemaUpdatePlaylistRequestPayload (line 1154) | type SchemaUpdatePlaylistRequestPayload =
  type SchemaReorderPlaylistsRequestPayload (line 1156) | type SchemaReorderPlaylistsRequestPayload =
  type SchemaTrackImages (line 1158) | type SchemaTrackImages = components['schemas']['TrackImages']
  type SchemaGetTracksRequestPayload (line 1159) | type SchemaGetTracksRequestPayload = components['schemas']['GetTracksReq...
  type SchemaJsonApiErrorSource (line 1160) | type SchemaJsonApiErrorSource = components['schemas']['JsonApiErrorSource']
  type SchemaJsonApiError (line 1161) | type SchemaJsonApiError = components['schemas']['JsonApiError']
  type SchemaJsonApiErrorDocument (line 1162) | type SchemaJsonApiErrorDocument = components['schemas']['JsonApiErrorDoc...
  type SchemaTrackAttachment (line 1163) | type SchemaTrackAttachment = components['schemas']['TrackAttachment']
  type SchemaTrackListItemAttributes (line 1164) | type SchemaTrackListItemAttributes = components['schemas']['TrackListIte...
  type SchemaArtistRelationship (line 1165) | type SchemaArtistRelationship = components['schemas']['ArtistRelationship']
  type SchemaArtistsRelationship (line 1166) | type SchemaArtistsRelationship = components['schemas']['ArtistsRelations...
  type SchemaTrackRelationships (line 1167) | type SchemaTrackRelationships = components['schemas']['TrackRelationships']
  type SchemaTrackListItemResource (line 1168) | type SchemaTrackListItemResource = components['schemas']['TrackListItemR...
  type SchemaJsonApiMetaWithPagingAndCursor (line 1169) | type SchemaJsonApiMetaWithPagingAndCursor =
  type SchemaOmitTypeClass (line 1171) | type SchemaOmitTypeClass = components['schemas']['OmitTypeClass']
  type SchemaIncludedArtistOutput (line 1172) | type SchemaIncludedArtistOutput = components['schemas']['IncludedArtistO...
  type SchemaGetTrackListOutput (line 1173) | type SchemaGetTrackListOutput = components['schemas']['GetTrackListOutput']
  type SchemaTrackListItemAttributesForPlaylist (line 1174) | type SchemaTrackListItemAttributesForPlaylist =
  type SchemaTrackListItemResourceForPlaylist (line 1176) | type SchemaTrackListItemResourceForPlaylist =
  type SchemaJsonApiMeta (line 1178) | type SchemaJsonApiMeta = components['schemas']['JsonApiMeta']
  type SchemaGetTracksForPlaylistOutput (line 1179) | type SchemaGetTracksForPlaylistOutput = components['schemas']['GetTracks...
  type SchemaArtistRef (line 1180) | type SchemaArtistRef = components['schemas']['ArtistRef']
  type SchemaTrackDetailsAttributes (line 1181) | type SchemaTrackDetailsAttributes = components['schemas']['TrackDetailsA...
  type SchemaTrackDetailsResource (line 1182) | type SchemaTrackDetailsResource = components['schemas']['TrackDetailsRes...
  type SchemaGetTrackDetailsOutput (line 1183) | type SchemaGetTrackDetailsOutput = components['schemas']['GetTrackDetail...
  type SchemaReactionOutput (line 1184) | type SchemaReactionOutput = components['schemas']['ReactionOutput']
  type SchemaGetPlaylistsRequestPayload (line 1185) | type SchemaGetPlaylistsRequestPayload = components['schemas']['GetPlayli...
  type SchemaJsonApiMetaWithPaging (line 1186) | type SchemaJsonApiMetaWithPaging = components['schemas']['JsonApiMetaWit...
  type SchemaGetPlaylistsOutput (line 1187) | type SchemaGetPlaylistsOutput = components['schemas']['GetPlaylistsOutput']
  type SchemaReorderTracksRequestPayload (line 1188) | type SchemaReorderTracksRequestPayload = components['schemas']['ReorderT...
  type SchemaUpdateTrackRequestPayload (line 1189) | type SchemaUpdateTrackRequestPayload = components['schemas']['UpdateTrac...
  type SchemaAddTrackToPlaylistRequestPayload (line 1190) | type SchemaAddTrackToPlaylistRequestPayload =
  type SchemaCreateArtistRequestPayload (line 1192) | type SchemaCreateArtistRequestPayload = components['schemas']['CreateArt...
  type SchemaLoginRequestPayload (line 1193) | type SchemaLoginRequestPayload = components['schemas']['LoginRequestPayl...
  type SchemaRefreshOutput (line 1194) | type SchemaRefreshOutput = components['schemas']['RefreshOutput']
  type SchemaBadRequestException (line 1195) | type SchemaBadRequestException = components['schemas']['BadRequestExcept...
  type SchemaUnauthorizedException (line 1196) | type SchemaUnauthorizedException = components['schemas']['UnauthorizedEx...
  type SchemaRefreshRequestPayload (line 1197) | type SchemaRefreshRequestPayload = components['schemas']['RefreshRequest...
  type SchemaLogoutRequestPayload (line 1198) | type SchemaLogoutRequestPayload = components['schemas']['LogoutRequestPa...
  type SchemaGetMeOutput (line 1199) | type SchemaGetMeOutput = components['schemas']['GetMeOutput']
  type SchemaCreateTagRequestPayload (line 1200) | type SchemaCreateTagRequestPayload = components['schemas']['CreateTagReq...
  type SchemaBinaryFile (line 1201) | type SchemaBinaryFile = components['schemas']['BinaryFile']
  type $defs (line 1202) | type $defs = Record<string, never>
  type operations (line 1203) | interface operations {
  type PathsPlaylistsGetParametersQuerySortBy (line 2610) | enum PathsPlaylistsGetParametersQuerySortBy {
  type PathsPlaylistsGetParametersQuerySortDirection (line 2614) | enum PathsPlaylistsGetParametersQuerySortDirection {
  type PathsPlaylistsTracksGetParametersQuerySortBy (line 2618) | enum PathsPlaylistsTracksGetParametersQuerySortBy {
  type PathsPlaylistsTracksGetParametersQueryPaginationType (line 2622) | enum PathsPlaylistsTracksGetParametersQueryPaginationType {
  type ImageSizeType (line 2626) | enum ImageSizeType {
  type ReactionValue (line 2631) | enum ReactionValue {

FILE: apps/react-effector-fsd/src/shared/api/utils/json-api-error.ts
  type JsonApiError (line 1) | interface JsonApiError {
  type JsonApiErrorDocument (line 10) | interface JsonApiErrorDocument {
  type ExtractError (line 15) | type ExtractError<T> = T extends { error?: infer E } ? E : unknown
  type JsonApiError (line 18) | interface JsonApiError {
  type JsonApiErrorDocument (line 27) | interface JsonApiErrorDocument {
  function isJsonApiErrorDocument (line 32) | function isJsonApiErrorDocument(error: unknown): error is JsonApiErrorDo...
  function parseJsonApiErrors (line 41) | function parseJsonApiErrors(errorDoc: JsonApiErrorDocument): {

FILE: apps/react-effector-fsd/src/shared/api/utils/request-wrapper.ts
  type ExtractData (line 10) | type ExtractData<T> = T extends { data?: infer D } ? NonNullable<D> : never
  function requestWrapper (line 12) | async function requestWrapper<P extends Promise<{ data?: unknown; error?...

FILE: apps/react-effector-fsd/src/shared/components/AudioPlayer/AudioPlayer.tsx
  type PlayerProps (line 19) | type PlayerProps = {

FILE: apps/react-effector-fsd/src/shared/components/Autocomplete/Autocomplete.stories.tsx
  type Story (line 20) | type Story = StoryObj<typeof meta>

FILE: apps/react-effector-fsd/src/shared/components/Autocomplete/Autocomplete.tsx
  type AutocompleteOption (line 18) | type AutocompleteOption = {
  type AutocompleteProps (line 24) | type AutocompleteProps = {

FILE: apps/react-effector-fsd/src/shared/components/Button/Button.stories.tsx
  type Story (line 15) | type Story = StoryObj<typeof meta>

FILE: apps/react-effector-fsd/src/shared/components/Button/Button.tsx
  type ButtonVariant (line 6) | type ButtonVariant = 'primary' | 'secondary'
  type ButtonProps (line 8) | type ButtonProps<T extends ElementType = 'button'> = {

FILE: apps/react-effector-fsd/src/shared/components/Card/Card.stories.tsx
  type Story (line 17) | type Story = StoryObj<typeof meta>

FILE: apps/react-effector-fsd/src/shared/components/Card/Card.tsx
  type CardProps (line 6) | type CardProps<T extends ElementType = 'div'> = {

FILE: apps/react-effector-fsd/src/shared/components/Dialog/Dialog.tsx
  type DialogContextType (line 8) | type DialogContextType = {
  type DialogProps (line 22) | type DialogProps = {
  type DialogHeaderProps (line 70) | type DialogHeaderProps = {
  type DialogContentProps (line 99) | type DialogContentProps = {
  type DialogFooterProps (line 112) | type DialogFooterProps = {

FILE: apps/react-effector-fsd/src/shared/components/DropdownMenu/DropdownMenu.stories.tsx
  type Story (line 24) | type Story = StoryObj<typeof meta>

FILE: apps/react-effector-fsd/src/shared/components/DropdownMenu/DropdownMenu.tsx
  type DropdownMenuContextType (line 16) | type DropdownMenuContextType = {
  type DropdownMenuProps (line 37) | type DropdownMenuProps = {
  type DropdownMenuTriggerProps (line 102) | type DropdownMenuTriggerProps = {
  type DropdownMenuContentProps (line 141) | type DropdownMenuContentProps = {
  type DropdownMenuItemProps (line 229) | type DropdownMenuItemProps<T extends ElementType = 'button'> = {
  type DropdownMenuSeparatorProps (line 272) | type DropdownMenuSeparatorProps = {

FILE: apps/react-effector-fsd/src/shared/components/Hashtag/Tag.stories.tsx
  type Story (line 17) | type Story = StoryObj<typeof meta>

FILE: apps/react-effector-fsd/src/shared/components/Hashtag/Tag.tsx
  type HashtagProps (line 6) | type HashtagProps<T extends ElementType = 'button'> = {

FILE: apps/react-effector-fsd/src/shared/components/IconButton/IconButton.stories.tsx
  type Story (line 25) | type Story = StoryObj<typeof meta>

FILE: apps/react-effector-fsd/src/shared/components/IconButton/IconButton.tsx
  type IconButtonProps (line 6) | type IconButtonProps = {

FILE: apps/react-effector-fsd/src/shared/components/ImageUploader/ImageUploader.stories.tsx
  type Story (line 17) | type Story = StoryObj<typeof meta>

FILE: apps/react-effector-fsd/src/shared/components/ImageUploader/ImageUploader.tsx
  type ImageUploaderProps (line 10) | type ImageUploaderProps = {

FILE: apps/react-effector-fsd/src/shared/components/Pagination/Pagination.stories.tsx
  type Story (line 18) | type Story = StoryObj<typeof meta>

FILE: apps/react-effector-fsd/src/shared/components/Pagination/Pagination.tsx
  type PaginationProps (line 9) | type PaginationProps = {
  constant MAX_VISIBLE_PAGES (line 16) | const MAX_VISIBLE_PAGES = 5

FILE: apps/react-effector-fsd/src/shared/components/Progress/Progress.stories.tsx
  type Story (line 19) | type Story = StoryObj<typeof meta>

FILE: apps/react-effector-fsd/src/shared/components/Progress/Progress.tsx
  type ProgressProps (line 6) | type ProgressProps = {

FILE: apps/react-effector-fsd/src/shared/components/ReactionButtons/ReactionButtons.stories.tsx
  type Story (line 18) | type Story = StoryObj<typeof meta>

FILE: apps/react-effector-fsd/src/shared/components/ReactionButtons/ReactionButtons.tsx
  type CurrentUserReaction (line 10) | type CurrentUserReaction = ReactionValue
  type ReactionButtonsProps (line 12) | type ReactionButtonsProps = {
  constant SIZE_MAP (line 21) | const SIZE_MAP = {

FILE: apps/react-effector-fsd/src/shared/components/SearchField/SearchField.stories.tsx
  type Story (line 15) | type Story = StoryObj<typeof meta>

FILE: apps/react-effector-fsd/src/shared/components/SearchField/SearchField.tsx
  type SearchFieldProps (line 8) | type SearchFieldProps = {

FILE: apps/react-effector-fsd/src/shared/components/Select/Select.stories.tsx
  type Story (line 16) | type Story = StoryObj<typeof meta>

FILE: apps/react-effector-fsd/src/shared/components/Select/Select.tsx
  type SelectOption (line 10) | type SelectOption = {
  type SelectProps (line 16) | type SelectProps = {

FILE: apps/react-effector-fsd/src/shared/components/SortSelect/Select.tsx
  type SelectOption (line 10) | type SelectOption = {
  type SelectProps (line 16) | type SelectProps = {

FILE: apps/react-effector-fsd/src/shared/components/Table/Table.stories.tsx
  type Story (line 18) | type Story = StoryObj<typeof meta>

FILE: apps/react-effector-fsd/src/shared/components/Table/Table.tsx
  type TableProps (line 10) | type TableProps = {
  type TableHeadProps (line 27) | type TableHeadProps = {
  type TableBodyProps (line 44) | type TableBodyProps = {
  type TableRowProps (line 61) | type TableRowProps = {
  type TableHeaderCellProps (line 78) | type TableHeaderCellProps = {
  type TableCellProps (line 95) | type TableCellProps = {

FILE: apps/react-effector-fsd/src/shared/components/Tabs/Tabs.tsx
  type TabsContextType (line 6) | type TabsContextType = {
  type TabsProps (line 25) | type TabsProps = {
  type TabsListProps (line 63) | type TabsListProps = {
  type TabsTriggerProps (line 76) | type TabsTriggerProps = {
  type TabsContentProps (line 108) | type TabsContentProps = {

FILE: apps/react-effector-fsd/src/shared/components/TagEditor/TagEditor.tsx
  type TagEditorProps (line 12) | type TagEditorProps = {

FILE: apps/react-effector-fsd/src/shared/components/TextField/TextField.stories.tsx
  type Story (line 17) | type Story = StoryObj<typeof meta>

FILE: apps/react-effector-fsd/src/shared/components/TextField/TextField.tsx
  type TextFieldSize (line 8) | type TextFieldSize = 'm' | 'l'
  type TextFieldProps (line 10) | type TextFieldProps = {

FILE: apps/react-effector-fsd/src/shared/components/Textarea/Textarea.stories.tsx
  type Story (line 15) | type Story = StoryObj<typeof meta>

FILE: apps/react-effector-fsd/src/shared/components/Textarea/Textarea.tsx
  type TextareaProps (line 8) | type TextareaProps = {

FILE: apps/react-effector-fsd/src/shared/components/Typography/Typography.stories.tsx
  type Story (line 15) | type Story = StoryObj<typeof meta>

FILE: apps/react-effector-fsd/src/shared/components/Typography/Typography.tsx
  constant VARIANT_DEFAULT_COMPONENT (line 7) | const VARIANT_DEFAULT_COMPONENT: Record<string, ElementType> = {
  type TypographyVariant (line 18) | type TypographyVariant =
  type Props (line 29) | type Props<T extends ElementType> = {

FILE: apps/react-effector-fsd/src/shared/config/config.ts
  constant API_BASE_URL (line 1) | const API_BASE_URL = import.meta.env.VITE_API_BASE_URL
  constant API_KEY (line 2) | const API_KEY = import.meta.env.VITE_API_KEY
  constant CURRENT_APP_DOMAIN (line 3) | const CURRENT_APP_DOMAIN = import.meta.env.VITE_BASE_URL

FILE: apps/react-effector-fsd/src/widgets/layout/ui/Sidebar/MenuLinks/MenuLinks.tsx
  type MenuLink (line 9) | type MenuLink = {
  type MenuButton (line 15) | type MenuButton = {

FILE: apps/react-native-expo/app.config.ts
  constant PROFILE (line 3) | const PROFILE =

FILE: apps/react-native-expo/app/(app)/_layout.tsx
  function AppLayout (line 13) | function AppLayout() {

FILE: apps/react-native-expo/app/(app)/index.tsx
  function Home (line 8) | function Home() {

FILE: apps/react-native-expo/app/(app)/library/library.tsx
  function Library (line 3) | function Library() {

FILE: apps/react-native-expo/app/(app)/playlists/playlists.tsx
  function Playlists (line 3) | function Playlists() {

FILE: apps/react-native-expo/app/(app)/tracks/tracks.tsx
  function Tracks (line 3) | function Tracks() {

FILE: apps/react-native-expo/app/(auth)/_layout.tsx
  function AuthLayout (line 5) | function AuthLayout() {

FILE: apps/react-native-expo/app/(auth)/login.tsx
  function Login (line 13) | function Login() {

FILE: apps/react-native-expo/app/_layout.tsx
  function RootLayout (line 17) | function RootLayout() {

FILE: apps/react-native-expo/features/auth/components/LoginButton/LoginButton.tsx
  type LoginButtonPropsT (line 10) | type LoginButtonPropsT = {}
  constant AUTH_URL (line 14) | const AUTH_URL = `${API_ROOT}${VERSION_ROOT}/auth/oauth-redirect?callbac...

FILE: apps/react-native-expo/features/auth/model/api/auth-instanse/auth-instanse.ts
  class apiAuthInstance (line 10) | class apiAuthInstance {
    method me (line 13) | static me() {
    method login (line 16) | static login(arg: RequestLoginT) {
    method logout (line 24) | static logout(arg: RequestLogoutT) {

FILE: apps/react-native-expo/features/auth/model/config/oauth.ts
  constant REDIRECT_URI_EXPO (line 4) | const REDIRECT_URI_EXPO = `${base}/oauth/callback`

FILE: apps/react-native-expo/features/auth/model/context/AuthContext.tsx
  type LoginParams (line 8) | type LoginParams = { code: string; redirectUri: string }
  type AuthContextT (line 9) | type AuthContextT = {

FILE: apps/react-native-expo/features/auth/model/types/api.types.ts
  type ResMeT (line 1) | type ResMeT = {
  type RequestLoginT (line 6) | type RequestLoginT = {
  type RequestLogoutT (line 13) | type RequestLogoutT = {
  type ResponseLoginT (line 20) | type ResponseLoginT = {

FILE: apps/react-native-expo/features/auth/model/utils/expoUrlToHttpCallback.ts
  function expoUrlToHttpCallback (line 1) | function expoUrlToHttpCallback(expoUrl: string): string {

FILE: apps/react-native-expo/features/playlists/model/api/playlist-instance/playlist-instance.ts
  class AuthPlaylistInstance (line 5) | class AuthPlaylistInstance {
    method getPlaylist (line 8) | static getPlaylist() {

FILE: apps/react-native-expo/shared/api/api-root/api-root-instanse.ts
  type ApiPrefixT (line 15) | type ApiPrefixT = (typeof API_PREFIX_ROOT)[keyof typeof API_PREFIX_ROOT]
  constant RETRY_HEADER (line 18) | const RETRY_HEADER = RETRY_HEADER_CONST

FILE: apps/react-native-expo/shared/api/api-root/api-root.ts
  type Extra (line 3) | type Extra = {
  constant API_ROOT (line 27) | const API_ROOT = (extra.API_BASE_URL ?? '').trim()
  constant API_KEY (line 28) | const API_KEY = (extra.API_API_KEY ?? '').trim()
  constant VERSION_ROOT (line 29) | const VERSION_ROOT = '1.0'
  constant API_PREFIX_ROOT (line 31) | const API_PREFIX_ROOT = {

FILE: apps/react-native-expo/shared/api/query-persist/query-presist.ts
  function setupQueryPersist (line 19) | function setupQueryPersist() {

FILE: apps/react-native-expo/shared/consts/consts.ts
  constant CALLBACK_URL (line 1) | const CALLBACK_URL = 'http://localhost:8081/callback'
  constant RETRY_HEADER_CONST (line 2) | const RETRY_HEADER_CONST = 'x-musicfun-retried'

FILE: apps/react-native-expo/shared/consts/key-storage/key-storage.ts
  constant KEY_STORAGE (line 1) | const KEY_STORAGE = {

FILE: apps/react-native-expo/shared/providers/reactQueryProviders/ReactQueryProviders.tsx
  function ReactQueryProvider (line 11) | function ReactQueryProvider({ children }: PropsWithChildren) {

FILE: apps/react-native-expo/shared/storage/tokenStorage.ts
  type Tokens (line 5) | type Tokens = { accessToken: string; refreshToken: string }

FILE: apps/react-native-expo/shared/styles/tokens.ts
  constant COLORS (line 1) | const COLORS = {
  constant GAPS (line 20) | const GAPS = {
  constant RADIUS (line 25) | const RADIUS = {
  constant FONTS_SIZES (line 29) | const FONTS_SIZES = {

FILE: apps/react-native-expo/shared/styles/tokens.type.ts
  type ColorTheme (line 3) | type ColorTheme = keyof typeof COLORS
  type GapName (line 4) | type GapName = keyof typeof GAPS
  type RadiusName (line 5) | type RadiusName = keyof typeof RADIUS
  type FontName (line 6) | type FontName = keyof typeof FONTS_SIZES
  type DarkColorKey (line 8) | type DarkColorKey = keyof (typeof COLORS)['DARK']
  type LightColorKey (line 9) | type LightColorKey = keyof (typeof COLORS)['LIGHT']

FILE: apps/react-native-expo/shared/ui/Button/Button.type.tsx
  type ButtonProps (line 3) | type ButtonProps = PressableProps & {

FILE: apps/reatom/src/app/entrypoint/main.tsx
  type MutationMeta (line 21) | type MutationMeta = {
  type Register (line 30) | interface Register {

FILE: apps/reatom/src/entities/playlist/ui/PlaylistCard/PlaylistCard.stories.tsx
  type Story (line 15) | type Story = StoryObj<typeof PlaylistCard>

FILE: apps/reatom/src/entities/playlist/ui/PlaylistCard/PlaylistCard.tsx
  type PlaylistCardPropsBase (line 11) | type PlaylistCardPropsBase = {
  type PlaylistCardProps (line 18) | type PlaylistCardProps = PlaylistCardPropsBase & {

FILE: apps/reatom/src/entities/playlist/ui/PlaylistItem/PlaylistItem.types.ts
  type CurrentUserReaction (line 4) | type CurrentUserReaction = components['schemas']['ReactionValue']
  type PlaylistItemProps (line 6) | interface PlaylistItemProps {

FILE: apps/reatom/src/features/artists/api/artists-api.ts
  constant MOCK_ARTISTS (line 1) | const MOCK_ARTISTS = [

FILE: apps/reatom/src/features/artists/ui/ArtistCard/ArtistCard.stories.tsx
  type Story (line 12) | type Story = StoryObj<typeof ArtistCard>

FILE: apps/reatom/src/features/artists/ui/ArtistCard/ArtistCard.tsx
  type Props (line 5) | type Props = {

FILE: apps/reatom/src/features/auth/types/auth-api.types.ts
  type RefreshOutput (line 4) | type RefreshOutput = components['schemas']['RefreshOutput']
  type RefreshRequestPayload (line 6) | type RefreshRequestPayload = components['schemas']['RefreshRequestPayload']
  type LoginRequestPayload (line 8) | type LoginRequestPayload = components['schemas']['LoginRequestPayload']

FILE: apps/reatom/src/features/auth/ui/ProfileDropdownMenu/ProfileDropdownMenu.stories.tsx
  type Story (line 15) | type Story = StoryObj<typeof ProfileDropdownMenu>

FILE: apps/reatom/src/features/playlists/api/playlistsApi.ts
  type CurrentUserReaction (line 37) | enum CurrentUserReaction {
  constant MOCK_PLAYLISTS (line 43) | const MOCK_PLAYLISTS: SchemaGetPlaylistOutput[] = [
  constant MOCK_PLAYLIST (line 370) | const MOCK_PLAYLIST = {

FILE: apps/reatom/src/features/playlists/model/model.tsx
  method load (line 12) | async load(page: number) {

FILE: apps/reatom/src/features/playlists/ui/PlaylistOverview/PlaylistOverview.stories.tsx
  type Story (line 14) | type Story = StoryObj<typeof PlaylistOverview>

FILE: apps/reatom/src/features/playlists/ui/PlaylistOverview/PlaylistOverview.tsx
  type PlaylistOverviewProps (line 9) | type PlaylistOverviewProps = {

FILE: apps/reatom/src/features/reactions/ui/ReactionProvider/ReactionProvider.tsx
  type ReactionValue (line 4) | type ReactionValue = 1 | -1 | 0
  type ReactionProviderProps (line 6) | interface ReactionProviderProps {
  type ReactionType (line 21) | enum ReactionType {

FILE: apps/reatom/src/features/tags/api/tags-api.ts
  constant MOCK_HASHTAGS (line 1) | const MOCK_HASHTAGS = [
  constant MOCK_5_HASHTAGS (line 13) | const MOCK_5_HASHTAGS = MOCK_HASHTAGS.slice(0, 5)
  type TagDto (line 15) | type TagDto = {

FILE: apps/reatom/src/features/tags/ui/TagsList/TagsList.stories.tsx
  type Story (line 13) | type Story = StoryObj<typeof TagsList>

FILE: apps/reatom/src/features/tracks/api/tracksApi.ts
  constant MOCK_TRACKS (line 3) | const MOCK_TRACKS = [

FILE: apps/reatom/src/features/tracks/api/types.ts
  type CurrentUserReaction (line 1) | enum CurrentUserReaction {

FILE: apps/reatom/src/features/tracks/ui/TrackCard/TrackCard.stories.tsx
  type Story (line 12) | type Story = StoryObj<typeof TrackCard>

FILE: apps/reatom/src/features/tracks/ui/TrackCard/TrackCard.tsx
  type Props (line 7) | type Props = {

FILE: apps/reatom/src/features/tracks/ui/TrackOverview/TrackOverview.stories.tsx
  type Story (line 14) | type Story = StoryObj<typeof TrackOverview>

FILE: apps/reatom/src/features/tracks/ui/TrackOverview/TrackOverview.tsx
  type TrackOverviewProps (line 9) | type TrackOverviewProps = {

FILE: apps/reatom/src/features/tracks/ui/TracksTable/TrackTable.stories.tsx
  type Story (line 24) | type Story = StoryObj<typeof TracksTable>
  type ReactionsProps (line 26) | type ReactionsProps =
  type TrackRowData (line 38) | type TrackRowData = {

FILE: apps/reatom/src/features/tracks/ui/TracksTable/TracksTable.tsx
  type TableColumn (line 13) | type TableColumn = {
  constant TABLE_COLUMNS (line 18) | const TABLE_COLUMNS: TableColumn[] = [
  type TracksTableProps (line 43) | type TracksTableProps<T extends TrackRowData> = {
  type ReactionsProps (line 48) | type ReactionsProps =
  type TrackRowData (line 60) | type TrackRowData = {

FILE: apps/reatom/src/layout/Sidebar/MenuLinks/MenuLinks.tsx
  type MenuLink (line 9) | type MenuLink = {
  type MenuButton (line 15) | type MenuButton = {

FILE: apps/reatom/src/pages/PlaylistsPage/PlaylistsPage.tsx
  constant PAGE_SIZE (line 20) | const PAGE_SIZE = 5
  constant DEFAULT_PAGE (line 21) | const DEFAULT_PAGE = 1

FILE: apps/reatom/src/pages/PlaylistsPage/PlaylistsPage.types.ts
  type SortOption (line 3) | type SortOption = 'mostLiked' | 'leastLiked' | 'newest' | 'oldest'
  type ISortConfig (line 5) | interface ISortConfig {

FILE: apps/reatom/src/pages/common/ContentList/ContentList.tsx
  type ContentListProps (line 7) | type ContentListProps<T> = {

FILE: apps/reatom/src/pages/common/PageWrapper/PageWrapper.tsx
  type PageWrapperProps (line 5) | type PageWrapperProps = {

FILE: apps/reatom/src/shared/api/client.ts
  function makeRefreshToken (line 28) | function makeRefreshToken(): Promise<string> {
  method onRequest (line 60) | async onRequest({ request }) {
  method onResponse (line 69) | async onResponse({ request, response }) {
  constant LOCAL_HOSTNAMES (line 106) | const LOCAL_HOSTNAMES = new Set(['localhost', '127.0.0.1', '::1', '0.0.0...
  function isLocalClient (line 108) | function isLocalClient(): boolean {
  function assertApiConfig (line 114) | function assertApiConfig() {

FILE: apps/reatom/src/shared/api/schema.ts
  type paths (line 6) | interface paths {
  type webhooks (line 554) | type webhooks = Record<string, never>
  type components (line 555) | interface components {
  type SchemaUserOutputDto (line 1199) | type SchemaUserOutputDto = components['schemas']['UserOutputDTO']
  type SchemaImageSizeType (line 1200) | type SchemaImageSizeType = components['schemas']['ImageSizeType']
  type SchemaImageDto (line 1201) | type SchemaImageDto = components['schemas']['ImageDto']
  type SchemaPlaylistImagesOutputDto (line 1202) | type SchemaPlaylistImagesOutputDto = components['schemas']['PlaylistImag...
  type SchemaGetTagOutput (line 1203) | type SchemaGetTagOutput = components['schemas']['GetTagOutput']
  type SchemaReactionValue (line 1204) | type SchemaReactionValue = components['schemas']['ReactionValue']
  type SchemaPlaylistAttributesDto (line 1205) | type SchemaPlaylistAttributesDto = components['schemas']['PlaylistAttrib...
  type SchemaPlaylistListItemJsonApiData (line 1206) | type SchemaPlaylistListItemJsonApiData = components['schemas']['Playlist...
  type SchemaGetMyPlaylistsOutput (line 1207) | type SchemaGetMyPlaylistsOutput = components['schemas']['GetMyPlaylistsO...
  type SchemaCreatePlaylistRequestPayload (line 1208) | type SchemaCreatePlaylistRequestPayload =
  type SchemaPlaylistOutputAttributes (line 1210) | type SchemaPlaylistOutputAttributes = components['schemas']['PlaylistOut...
  type SchemaPlaylistOutput (line 1211) | type SchemaPlaylistOutput = components['schemas']['PlaylistOutput']
  type SchemaGetPlaylistOutput (line 1212) | type SchemaGetPlaylistOutput = components['schemas']['GetPlaylistOutput']
  type SchemaUpdatePlaylistRequestPayload (line 1213) | type SchemaUpdatePlaylistRequestPayload =
  type SchemaReorderPlaylistsRequestPayload (line 1215) | type SchemaReorderPlaylistsRequestPayload =
  type SchemaGetImagesOutput (line 1217) | type SchemaGetImagesOutput = components['schemas']['GetImagesOutput']
  type SchemaGetTracksRequestPayload (line 1218) | type SchemaGetTracksRequestPayload = components['schemas']['GetTracksReq...
  type SchemaJsonApiErrorSource (line 1219) | type SchemaJsonApiErrorSource = components['schemas']['JsonApiErrorSource']
  type SchemaJsonApiError (line 1220) | type SchemaJsonApiError = components['schemas']['JsonApiError']
  type SchemaJsonApiErrorDocument (line 1221) | type SchemaJsonApiErrorDocument = components['schemas']['JsonApiErrorDoc...
  type SchemaAttachmentDto (line 1222) | type SchemaAttachmentDto = components['schemas']['AttachmentDto']
  type SchemaTrackListItemOutputAttributes (line 1223) | type SchemaTrackListItemOutputAttributes =
  type SchemaArtistRelationship (line 1225) | type SchemaArtistRelationship = components['schemas']['ArtistRelationship']
  type SchemaArtistsRelationship (line 1226) | type SchemaArtistsRelationship = components['schemas']['ArtistsRelations...
  type SchemaTrackRelationships (line 1227) | type SchemaTrackRelationships = components['schemas']['TrackRelationships']
  type SchemaTrackListItemOutput (line 1228) | type SchemaTrackListItemOutput = components['schemas']['TrackListItemOut...
  type SchemaJsonApiMetaWithPagingAndCursor (line 1229) | type SchemaJsonApiMetaWithPagingAndCursor =
  type SchemaOmitTypeClass (line 1231) | type SchemaOmitTypeClass = components['schemas']['OmitTypeClass']
  type SchemaIncludedArtistOutput (line 1232) | type SchemaIncludedArtistOutput = components['schemas']['IncludedArtistO...
  type SchemaGetTrackListOutput (line 1233) | type SchemaGetTrackListOutput = components['schemas']['GetTrackListOutput']
  type SchemaPlaylistTrackAttributes (line 1234) | type SchemaPlaylistTrackAttributes = components['schemas']['PlaylistTrac...
  type SchemaGetPlaylistTrackListOutputData (line 1235) | type SchemaGetPlaylistTrackListOutputData =
  type SchemaJsonApiMeta (line 1237) | type SchemaJsonApiMeta = components['schemas']['JsonApiMeta']
  type SchemaGetPlaylistTrackListOutput (line 1238) | type SchemaGetPlaylistTrackListOutput = components['schemas']['GetPlayli...
  type SchemaGetArtistOutput (line 1239) | type SchemaGetArtistOutput = components['schemas']['GetArtistOutput']
  type SchemaTrackDetailsAttributes (line 1240) | type SchemaTrackDetailsAttributes = components['schemas']['TrackDetailsA...
  type SchemaTrackDetailsData (line 1241) | type SchemaTrackDetailsData = components['schemas']['TrackDetailsData']
  type SchemaGetTrackDetailsOutput (line 1242) | type SchemaGetTrackDetailsOutput = components['schemas']['GetTrackDetail...
  type SchemaReactionOutput (line 1243) | type SchemaReactionOutput = components['schemas']['ReactionOutput']
  type SchemaGetPlaylistsRequestPayload (line 1244) | type SchemaGetPlaylistsRequestPayload = components['schemas']['GetPlayli...
  type SchemaJsonApiMetaWithPaging (line 1245) | type SchemaJsonApiMetaWithPaging = components['schemas']['JsonApiMetaWit...
  type SchemaGetPlaylistsOutput (line 1246) | type SchemaGetPlaylistsOutput = components['schemas']['GetPlaylistsOutput']
  type SchemaReorderTracksRequestPayload (line 1247) | type SchemaReorderTracksRequestPayload = components['schemas']['ReorderT...
  type SchemaUpdateTrackRequestPayload (line 1248) | type SchemaUpdateTrackRequestPayload = components['schemas']['UpdateTrac...
  type SchemaTrackOutputAttributes (line 1249) | type SchemaTrackOutputAttributes = components['schemas']['TrackOutputAtt...
  type SchemaTrackOutput (line 1250) | type SchemaTrackOutput = components['schemas']['TrackOutput']
  type SchemaGetTrackOutput (line 1251) | type SchemaGetTrackOutput = components['schemas']['GetTrackOutput']
  type SchemaAddTrackToPlaylistRequestPayload (line 1252) | type SchemaAddTrackToPlaylistRequestPayload =
  type SchemaCreateArtistRequestPayload (line 1254) | type SchemaCreateArtistRequestPayload = components['schemas']['CreateArt...
  type SchemaLoginRequestPayload (line 1255) | type SchemaLoginRequestPayload = components['schemas']['LoginRequestPayl...
  type SchemaRefreshOutput (line 1256) | type SchemaRefreshOutput = components['schemas']['RefreshOutput']
  type SchemaBadRequestException (line 1257) | type SchemaBadRequestException = components['schemas']['BadRequestExcept...
  type SchemaUnauthorizedException (line 1258) | type SchemaUnauthorizedException = components['schemas']['UnauthorizedEx...
  type SchemaRefreshRequestPayload (line 1259) | type SchemaRefreshRequestPayload = components['schemas']['RefreshRequest...
  type SchemaLogoutRequestPayload (line 1260) | type SchemaLogoutRequestPayload = components['schemas']['LogoutRequestPa...
  type SchemaGetMeOutput (line 1261) | type SchemaGetMeOutput = components['schemas']['GetMeOutput']
  type SchemaCreateTagRequestPayload (line 1262) | type SchemaCreateTagRequestPayload = components['schemas']['CreateTagReq...
  type SchemaBinaryFile (line 1263) | type SchemaBinaryFile = components['schemas']['BinaryFile']
  type $defs (line 1264) | type $defs = Record<string, never>
  type operations (line 1265) | interface operations {
  type PathsPlaylistsGetParametersQuerySortBy (line 2672) | enum PathsPlaylistsGetParametersQuerySortBy {
  type PathsPlaylistsGetParametersQuerySortDirection (line 2676) | enum PathsPlaylistsGetParametersQuerySortDirection {
  type PathsPlaylistsTracksGetParametersQuerySortBy (line 2680) | enum PathsPlaylistsTracksGetParametersQuerySortBy {
  type PathsPlaylistsTracksGetParametersQueryPaginationType (line 2684) | enum PathsPlaylistsTracksGetParametersQueryPaginationType {
  type ImageSizeType (line 2688) | enum ImageSizeType {
  type ReactionValue (line 2693) | enum ReactionValue {

FILE: apps/reatom/src/shared/api/types.ts
  type MainImage (line 3) | type MainImage = components['schemas']['ImageDto'][]

FILE: apps/reatom/src/shared/api/utils/json-api-error.ts
  type JsonApiError (line 1) | interface JsonApiError {
  type JsonApiErrorDocument (line 10) | interface JsonApiErrorDocument {
  type ExtractError (line 15) | type ExtractError<T> = T extends { error?: infer E } ? E : unknown
  type JsonApiError (line 18) | interface JsonApiError {
  type JsonApiErrorDocument (line 27) | interface JsonApiErrorDocument {
  function isJsonApiErrorDocument (line 32) | function isJsonApiErrorDocument(error: unknown): error is JsonApiErrorDo...
  function parseJsonApiErrors (line 41) | function parseJsonApiErrors(errorDoc: JsonApiErrorDocument): {

FILE: apps/reatom/src/shared/api/utils/request-wrapper.ts
  type ExtractData (line 10) | type ExtractData<T> = T extends { data?: infer D } ? NonNullable<D> : never
  function requestWrapper (line 12) | async function requestWrapper<P extends Promise<{ data?: unknown; error?...

FILE: apps/reatom/src/shared/components/AudioPlayer/AudioPlayer.tsx
  type PlayerProps (line 19) | type PlayerProps = {

FILE: apps/reatom/src/shared/components/Autocomplete/Autocomplete.stories.tsx
  type Story (line 20) | type Story = StoryObj<typeof meta>

FILE: apps/reatom/src/shared/components/Autocomplete/Autocomplete.tsx
  type AutocompleteOption (line 18) | type AutocompleteOption = {
  type AutocompleteProps (line 24) | type AutocompleteProps = {

FILE: apps/reatom/src/shared/components/Button/Button.stories.tsx
  type Story (line 15) | type Story = StoryObj<typeof meta>

FILE: apps/reatom/src/shared/components/Button/Button.tsx
  type ButtonVariant (line 6) | type ButtonVariant = 'primary' | 'secondary'
  type ButtonProps (line 8) | type ButtonProps<T extends ElementType = 'button'> = {

FILE: apps/reatom/src/shared/components/Card/Card.stories.tsx
  type Story (line 17) | type Story = StoryObj<typeof meta>

FILE: apps/reatom/src/shared/components/Card/Card.tsx
  type CardProps (line 6) | type CardProps<T extends ElementType = 'div'> = {

FILE: apps/reatom/src/shared/components/Dialog/Dialog.tsx
  type DialogContextType (line 8) | type DialogContextType = {
  type DialogProps (line 22) | type DialogProps = {
  type DialogHeaderProps (line 70) | type DialogHeaderProps = {
  type DialogContentProps (line 99) | type DialogContentProps = {
  type DialogFooterProps (line 112) | type DialogFooterProps = {

FILE: apps/reatom/src/shared/components/DropdownMenu/DropdownMenu.stories.tsx
  type Story (line 24) | type Story = StoryObj<typeof meta>

FILE: apps/reatom/src/shared/components/DropdownMenu/DropdownMenu.tsx
  type DropdownMenuContextType (line 16) | type DropdownMenuContextType = {
  type DropdownMenuProps (line 37) | type DropdownMenuProps = {
  type DropdownMenuTriggerProps (line 102) | type DropdownMenuTriggerProps = {
  type DropdownMenuContentProps (line 141) | type DropdownMenuContentProps = {
  type DropdownMenuItemProps (line 229) | type DropdownMenuItemProps<T extends ElementType = 'button'> = {
  type DropdownMenuSeparatorProps (line 272) | type DropdownMenuSeparatorProps = {

FILE: apps/reatom/src/shared/components/Hashtag/Tag.stories.tsx
  type Story (line 17) | type Story = StoryObj<typeof meta>

FILE: apps/reatom/src/shared/components/Hashtag/Tag.tsx
  type HashtagProps (line 6) | type HashtagProps<T extends ElementType = 'button'> = {

FILE: apps/reatom/src/shared/components/IconButton/IconButton.stories.tsx
  type Story (line 25) | type Story = StoryObj<typeof meta>

FILE: apps/reatom/src/shared/components/IconButton/IconButton.tsx
  type IconButtonProps (line 6) | type IconButtonProps = {

FILE: apps/reatom/src/shared/components/ImageUploader/ImageUploader.stories.tsx
  type Story (line 17) | type Story = StoryObj<typeof meta>

FILE: apps/reatom/src/shared/components/ImageUploader/ImageUploader.tsx
  type ImageUploaderProps (line 10) | type ImageUploaderProps = {

FILE: apps/reatom/src/shared/components/Pagination/Pagination.stories.tsx
  type Story (line 18) | type Story = StoryObj<typeof meta>

FILE: apps/reatom/src/shared/components/Pagination/Pagination.tsx
  type PaginationProps (line 9) | type PaginationProps = {
  constant MAX_VISIBLE_PAGES (line 16) | const MAX_VISIBLE_PAGES = 5

FILE: apps/reatom/src/shared/components/Progress/Progress.stories.tsx
  type Story (line 19) | type Story = StoryObj<typeof meta>

FILE: apps/reatom/src/shared/components/Progress/Progress.tsx
  type ProgressProps (line 6) | type ProgressProps = {

FILE: apps/reatom/src/shared/components/ReactionButtons/ReactionButtons.stories.tsx
  type Story (line 18) | type Story = StoryObj<typeof meta>

FILE: apps/reatom/src/shared/components/ReactionButtons/ReactionButtons.tsx
  type CurrentUserReaction (line 10) | type CurrentUserReaction = SchemaReactionValue
  type ReactionButtonsProps (line 12) | type ReactionButtonsProps = {
  constant SIZE_MAP (line 21) | const SIZE_MAP = {

FILE: apps/reatom/src/shared/components/SearchField/SearchField.stories.tsx
  type Story (line 15) | type Story = StoryObj<typeof meta>

FILE: apps/reatom/src/shared/components/SearchField/SearchField.tsx
  type SearchFieldProps (line 8) | type SearchFieldProps = {

FILE: apps/reatom/src/shared/components/Select/Select.stories.tsx
  type Story (line 16) | type Story = StoryObj<typeof meta>

FILE: apps/reatom/src/shared/components/Select/Select.tsx
  type SelectOption (line 10) | type SelectOption = {
  type SelectProps (line 16) | type SelectProps = {

FILE: apps/reatom/src/shared/components/SortSelect/Select.tsx
  type SelectOption (line 10) | type SelectOption = {
  type SelectProps (line 16) | type SelectProps = {

FILE: apps/reatom/src/shared/components/Table/Table.stories.tsx
  type Story (line 18) | type Story = StoryObj<typeof meta>

FILE: apps/reatom/src/shared/components/Table/Table.tsx
  type TableProps (line 10) | type TableProps = {
  type TableHeadProps (line 27) | type TableHeadProps = {
  type TableBodyProps (line 44) | type TableBodyProps = {
  type TableRowProps (line 61) | type TableRowProps = {
  type TableHeaderCellProps (line 78) | type TableHeaderCellProps = {
  type TableCellProps (line 95) | type TableCellProps = {

FILE: apps/reatom/src/shared/components/Tabs/Tabs.tsx
  type TabsContextType (line 6) | type TabsContextType = {
  type TabsProps (line 25) | type TabsProps = {
  type TabsListProps (line 63) | type TabsListProps = {
  type TabsTriggerProps (line 76) | type TabsTriggerProps = {
  type TabsContentProps (line 108) | type TabsContentProps = {

FILE: apps/reatom/src/shared/components/TagEditor/TagEditor.tsx
  type TagEditorProps (line 12) | type TagEditorProps = {

FILE: apps/reatom/src/shared/components/TextField/TextField.stories.tsx
  type Story (line 17) | type Story = StoryObj<typeof meta>

FILE: apps/reatom/src/shared/components/TextField/TextField.tsx
  type TextFieldSize (line 8) | type TextFieldSize = 'm' | 'l'
  type TextFieldProps (line 10) | type TextFieldProps = {

FILE: apps/reatom/src/shared/components/Textarea/Textarea.stories.tsx
  type Story (line 15) | type Story = StoryObj<typeof meta>

FILE: apps/reatom/src/shared/components/Textarea/Textarea.tsx
  type TextareaProps (line 8) | type TextareaProps = {

FILE: apps/reatom/src/shared/components/Typography/Typography.stories.tsx
  type Story (line 15) | type Story = StoryObj<typeof meta>

FILE: apps/reatom/src/shared/components/Typography/Typography.tsx
  constant VARIANT_DEFAULT_COMPONENT (line 7) | const VARIANT_DEFAULT_COMPONENT: Record<string, ElementType> = {
  type TypographyVariant (line 18) | type TypographyVariant =
  type Props (line 29) | type Props<T extends ElementType> = {

FILE: apps/reatom/src/shared/config/config.ts
  constant API_BASE_URL (line 1) | const API_BASE_URL = import.meta.env.VITE_API_BASE_URL
  constant API_KEY (line 2) | const API_KEY = import.meta.env.VITE_API_KEY
  constant CURRENT_APP_DOMAIN (line 3) | const CURRENT_APP_DOMAIN = import.meta.env.BASE_URL

FILE: apps/reatom/src/shared/ui/prerender-ready.tsx
  function PrerenderReady (line 4) | function PrerenderReady() {

FILE: apps/reatom/src/shared/utils/validators/getType.ts
  function getType (line 2) | function getType(object: any) {

FILE: apps/reatom/src/shared/utils/validators/inNun.ts
  function isNaN (line 1) | function isNaN(value: number) {

FILE: apps/reatom/src/shared/utils/validators/isArray.ts
  function isArray (line 4) | function isArray<T>(value: any): value is T[] {

FILE: apps/reatom/src/shared/utils/validators/isFunction.ts
  function isFunction (line 4) | function isFunction<TFunction extends (...args: any[]) => any>(value: an...

FILE: apps/reatom/src/shared/utils/validators/isNull.ts
  function isNull (line 1) | function isNull(value: unknown): value is null {

FILE: apps/reatom/src/shared/utils/validators/isObject.ts
  function isObject (line 5) | function isObject<T extends Record<string, any>>(value: any): value is T {

FILE: apps/reatom/src/shared/utils/validators/isUndefined.ts
  function isUndefined (line 3) | function isUndefined(value: unknown): value is undefined {

FILE: apps/reatom/src/shared/utils/validators/isValid.ts
  function isValid (line 4) | function isValid<T>(value: T | null | undefined): value is T {

FILE: apps/reatom/src/shared/utils/validators/isValidArray.ts
  function isValidArray (line 8) | function isValidArray(value: any) {

FILE: apps/reatom/src/widgets/Player/Player.tsx
  constant MOCK_TRACK (line 7) | const MOCK_TRACK = {

FILE: apps/rtk-query/src/app/store/store.ts
  type RootState (line 24) | type RootState = ReturnType<typeof store.getState>
  type AppDispatch (line 25) | type AppDispatch = typeof store.dispatch

FILE: apps/rtk-query/src/features/artists/api/artists-api.ts
  type Artist (line 3) | type Artist = {
  constant MOCK_ARTISTS (line 39) | const MOCK_ARTISTS = [

FILE: apps/rtk-query/src/features/artists/ui/ArtistCard/ArtistCard.stories.tsx
  type Story (line 12) | type Story = StoryObj<typeof ArtistCard>

FILE: apps/rtk-query/src/features/artists/ui/ArtistCard/ArtistCard.tsx
  type Props (line 5) | type Props = {

FILE: apps/rtk-query/src/features/auth/api/auth-api.ts
  method onQueryStarted (line 12) | async onQueryStarted(_arg, { dispatch, queryFulfilled }) {
  method onQueryStarted (line 27) | async onQueryStarted(_arg, { queryFulfilled }) {
  method onQueryStarted (line 44) | async onQueryStarted(_arg, { dispatch, queryFulfilled }) {

FILE: apps/rtk-query/src/features/auth/api/auth-api.types.ts
  type GetMeResponse (line 1) | type GetMeResponse = {
  type AuthTokensResponse (line 6) | type AuthTokensResponse = {
  type OAuthLoginArgs (line 11) | type OAuthLoginArgs = {

FILE: apps/rtk-query/src/features/playlists/api/mocks.ts
  constant MOCK_PLAYLISTS (line 3) | const MOCK_PLAYLISTS = [
  constant MOCK_PLAYLIST (line 335) | const MOCK_PLAYLIST = {

FILE: apps/rtk-query/src/features/playlists/api/playlistsApi.types.ts
  type CurrentUserReaction (line 3) | enum CurrentUserReaction {
  type Playlist (line 9) | type Playlist = {
  type PlaylistDetail (line 15) | type PlaylistDetail = {
  type Tag (line 21) | type Tag = {
  type BasePlaylistAttributes (line 27) | type BasePlaylistAttributes = {
  type PlaylistListAttributes (line 43) | type PlaylistListAttributes = BasePlaylistAttributes
  type PlaylistDetailAttributes (line 46) | type PlaylistDetailAttributes = BasePlaylistAttributes & {
  type PlaylistAttributes (line 51) | type PlaylistAttributes = PlaylistListAttributes
  type PlaylistsResponse (line 54) | type PlaylistsResponse = {
  type CreatePlaylistArgs (line 60) | type CreatePlaylistArgs = {
  type UpdatePlaylistArgs (line 65) | type UpdatePlaylistArgs = {
  type FetchPlaylistsArgs (line 71) | type FetchPlaylistsArgs = {

FILE: apps/rtk-query/src/features/playlists/ui/ChoosePlaylistModal/ChoosePlaylistModal.tsx
  function handleToggle (line 40) | function handleToggle(id: string) {

FILE: apps/rtk-query/src/features/playlists/ui/CreateEditPlaylistModal/CreateEditPlaylistModal.tsx
  type FormData (line 29) | type FormData = {

FILE: apps/rtk-query/src/features/playlists/ui/PlaylistActions/PlaylistActions.tsx
  type PlaylistActionsProps (line 13) | type PlaylistActionsProps = {

FILE: apps/rtk-query/src/features/playlists/ui/PlaylistCard/PlaylistCard.stories.tsx
  type Story (line 16) | type Story = StoryObj<typeof PlaylistCard>

FILE: apps/rtk-query/src/features/playlists/ui/PlaylistCard/PlaylistCard.tsx
  type PlaylistCardPropsBase (line 17) | type PlaylistCardPropsBase = {
  type PlaylistCardPropsWithReactions (line 30) | type PlaylistCardPropsWithReactions = PlaylistCardPropsBase & {
  type PlaylistCardPropsWithoutReactions (line 36) | type PlaylistCardPropsWithoutReactions = PlaylistCardPropsBase & {
  type PlaylistCardProps (line 40) | type PlaylistCardProps = PlaylistCardPropsWithReactions | PlaylistCardPr...

FILE: apps/rtk-query/src/features/playlists/ui/PlaylistCardSkeleton/PlaylistCardSkeleton.stories.tsx
  type Story (line 17) | type Story = StoryObj<typeof PlaylistCardSkeleton>

FILE: apps/rtk-query/src/features/playlists/ui/PlaylistCardSkeleton/PlaylistCardSkeleton.tsx
  type PlaylistCardSkeletonProps (line 8) | type PlaylistCardSkeletonProps = {

FILE: apps/rtk-query/src/features/playlists/ui/PlaylistOverview/PlaylistOverview.stories.tsx
  type Story (line 14) | type Story = StoryObj<typeof PlaylistOverview>

FILE: apps/rtk-query/src/features/playlists/ui/PlaylistOverview/PlaylistOverview.tsx
  type PlaylistOverviewProps (line 12) | type PlaylistOverviewProps = {

FILE: apps/rtk-query/src/features/playlists/ui/PlaylistRow/PlaylistRow.tsx
  type PlaylistRowProps (line 9) | type PlaylistRowProps = {

FILE: apps/rtk-query/src/features/profile/types/profile.type.ts
  type FullName (line 1) | type FullName = {
  type Profile (line 6) | type Profile = {

FILE: apps/rtk-query/src/features/profile/ui/EditProfileModal/EditProfileModal.tsx
  type FormData (line 31) | type FormData = {

FILE: apps/rtk-query/src/features/tags/api/tagsApi.ts
  constant MOCK_HASHTAGS (line 1) | const MOCK_HASHTAGS: Tag[] = [
  constant MOCK_5_HASHTAGS (line 13) | const MOCK_5_HASHTAGS = MOCK_HASHTAGS.slice(0, 5)
  type TagDto (line 15) | type TagDto = {

FILE: apps/rtk-query/src/features/tags/api/tagsApi.types.ts
  type Tag (line 1) | type Tag = {
  type TagAttributes (line 7) | type TagAttributes = {
  type TagResource (line 11) | type TagResource = {
  type GetTagsResponse (line 17) | type GetTagsResponse = {
  type GetTagResponse (line 21) | type GetTagResponse = {
  type CreateTagRequest (line 25) | type CreateTagRequest = {

FILE: apps/rtk-query/src/features/tags/ui/TagsList/TagsList.stories.tsx
  type Story (line 14) | type Story = StoryObj<typeof TagsList>

FILE: apps/rtk-query/src/features/tracks/api/mocks.ts
  type CurrentUserReaction (line 1) | enum CurrentUserReaction {
  constant MOCK_TRACKS (line 7) | const MOCK_TRACKS = [

FILE: apps/rtk-query/src/features/tracks/api/tracksApi.ts
  method onQueryStarted (line 171) | async onQueryStarted({ trackId }, { dispatch, getState, queryFulfilled }) {
  method onQueryStarted (line 245) | async onQueryStarted({ trackId }, { dispatch, getState, queryFulfilled }) {
  method onQueryStarted (line 319) | async onQueryStarted({ trackId }, { dispatch, getState, queryFulfilled }) {

FILE: apps/rtk-query/src/features/tracks/api/tracksApi.types.ts
  type TrackDetails (line 10) | type TrackDetails<T> = {
  type BaseAttributes (line 25) | type BaseAttributes = {
  type FetchTracksAttributes (line 36) | type FetchTracksAttributes = BaseAttributes & {
  type Artist (line 40) | type Artist = {
  type TrackDetailAttributes (line 45) | type TrackDetailAttributes = BaseAttributes & {
  type PlaylistItemAttributes (line 60) | type PlaylistItemAttributes = BaseAttributes & {
  type TrackAttachment (line 66) | type TrackAttachment = {
  type IncludedArtist (line 79) | type IncludedArtist = {
  type FetchTracksResponse (line 86) | type FetchTracksResponse = {
  type FetchTrackByIdResponse (line 92) | type FetchTrackByIdResponse = {
  type FetchPlaylistsTracksResponse (line 96) | type FetchPlaylistsTracksResponse = {
  type ApiTrack (line 101) | type ApiTrack = TrackDetails<FetchTracksAttributes>
  type FetchTracksArgs (line 104) | type FetchTracksArgs = {
  type UpdateTrackArgs (line 116) | type UpdateTrackArgs = {
  type TrackVisibility (line 126) | type TrackVisibility = 'private' | 'public'
  type TrackProcessingStatus (line 128) | type TrackProcessingStatus = 'uploaded' | 'converting' | 'ready'

FILE: apps/rtk-query/src/features/tracks/constants/index.ts
  constant FETCH_TRACK_BY_SCROLL_PAGE_SIZE (line 1) | const FETCH_TRACK_BY_SCROLL_PAGE_SIZE = 10

FILE: apps/rtk-query/src/features/tracks/ui/CreateEditTrackModal/CreateEditTrackModal.tsx
  type FormData (line 51) | type FormData = {

FILE: apps/rtk-query/src/features/tracks/ui/TrackActions/TrackActions.tsx
  type TrackActionsPropsBase (line 22) | type TrackActionsPropsBase = {
  type TrackActionsPropsWithReactions (line 29) | type TrackActionsPropsWithReactions = TrackActionsPropsBase & {
  type TrackActionsPropsWithoutReactions (line 35) | type TrackActionsPropsWithoutReactions = TrackActionsPropsBase & {
  type TrackActionsProps (line 41) | type TrackActionsProps = TrackActionsPropsWithReactions | TrackActionsPr...

FILE: apps/rtk-query/src/features/tracks/ui/TrackActions/TrackActionsMenu/TrackActionsMenu.tsx
  type TrackActionsMenuProps (line 21) | type TrackActionsMenuProps = {

FILE: apps/rtk-query/src/features/tracks/ui/TrackCard/TrackCard.stories.tsx
  type Story (line 15) | type Story = StoryObj<typeof TrackCard>

FILE: apps/rtk-query/src/features/tracks/ui/TrackCard/TrackCard.tsx
  type Props (line 20) | type Props = {

FILE: apps/rtk-query/src/features/tracks/ui/TrackInfoCell/TrackInfoCell.tsx
  type TrackInfoCellProps (line 12) | type TrackInfoCellProps = {

FILE: apps/rtk-query/src/features/tracks/ui/TrackOverview/TrackOverview.stories.tsx
  type Story (line 14) | type Story = StoryObj<typeof TrackOverview>

FILE: apps/rtk-query/src/features/tracks/ui/TrackOverview/TrackOverview.tsx
  type TrackOverviewProps (line 12) | type TrackOverviewProps = {

FILE: apps/rtk-query/src/features/tracks/ui/TrackRow/TrackRow.tsx
  type TrackRowProps (line 13) | type TrackRowProps<T> = {

FILE: apps/rtk-query/src/features/tracks/ui/TrackRowContainer/TrackRowContainer.tsx
  type TrackRowContainerProps (line 7) | type TrackRowContainerProps = {

FILE: apps/rtk-query/src/features/tracks/ui/TracksTable/TrackTable.stories.tsx
  type Story (line 24) | type Story = StoryObj<typeof TracksTable>
  type ReactionsProps (line 26) | type ReactionsProps =
  type TrackRowData (line 38) | type TrackRowData = {

FILE: apps/rtk-query/src/features/tracks/ui/TracksTable/TracksTable.tsx
  type TableColumn (line 14) | type TableColumn = {
  type TracksTableProps (line 19) | type TracksTableProps<T extends TrackRowData> = {
  type ReactionsProps (line 24) | type ReactionsProps =
  type TrackRowData (line 36) | type TrackRowData = {
  constant TABLE_COLUMNS (line 49) | const TABLE_COLUMNS: TableColumn[] = [

FILE: apps/rtk-query/src/features/tracks/ui/TracksTableSkeleton/TracksTableSkeleton.tsx
  type Props (line 5) | type Props = {

FILE: apps/rtk-query/src/features/tracks/utils/playlistSync.ts
  type PlaylistSyncParams (line 1) | type PlaylistSyncParams = {

FILE: apps/rtk-query/src/layout/Header/AccountMenu/AccountMenu.stories.tsx
  type Story (line 15) | type Story = StoryObj<typeof AccountMenu>

FILE: apps/rtk-query/src/layout/Header/AccountMenu/AccountMenu.tsx
  type AccountMenuProps (line 19) | type AccountMenuProps = {

FILE: apps/rtk-query/src/layout/Sidebar/MenuLinks/MenuLinks.tsx
  type MenuLink (line 16) | type MenuLink = {
  type MenuButton (line 22) | type MenuButton = {

FILE: apps/rtk-query/src/pages/MainPage/MainPage.tsx
  constant NEW_TRACKS_PLAYLIST_ID (line 22) | const NEW_TRACKS_PLAYLIST_ID = 'new-tracks'

FILE: apps/rtk-query/src/pages/PlaylistPage/ui/ControlPanel/ControlPanel.tsx
  type ControlPanelProps (line 23) | type ControlPanelProps = {

FILE: apps/rtk-query/src/pages/UserPage/ui/UserInfo/UserStats/UserStats.tsx
  type UserStatsProps (line 7) | type UserStatsProps = {

FILE: apps/rtk-query/src/pages/common/hooks/usePageBackgroundColor.ts
  constant DEFAULT_BACKGROUND_COLOR (line 3) | const DEFAULT_BACKGROUND_COLOR = '#3333a3'

FILE: apps/rtk-query/src/pages/common/ui/ContentList/ContentList.tsx
  type ContentListProps (line 7) | type ContentListProps<T> = {
  constant SKELETON_ITEM_COUNT (line 18) | const SKELETON_ITEM_COUNT = 10

FILE: apps/rtk-query/src/pages/common/ui/PageWithHeader/PageWithHeader.tsx
  type PageWithHeaderProps (line 5) | type PageWithHeaderProps = {

FILE: apps/rtk-query/src/pages/common/ui/PageWithoutHeader/PageWithoutHeader.tsx
  type PageWithoutHeaderProps (line 5) | type PageWithoutHeaderProps = {

FILE: apps/rtk-query/src/pages/common/ui/SearchTags/SearchTags.tsx
  type SearchType (line 10) | type SearchType = 'tags' | 'artists'
  type SearchTagsProps (line 12) | type SearchTagsProps = {

FILE: apps/rtk-query/src/player/playerHooks.ts
  function usePlayerControls (line 74) | function usePlayerControls() {
  function usePlaybackState (line 97) | function usePlaybackState() {
  function useCurrentTrack (line 116) | function useCurrentTrack() {
  function usePlaybackProgress (line 133) | function usePlaybackProgress() {
  function useTrackPlaybackState (line 160) | function useTrackPlaybackState(trackId: string): TrackPlaybackState {
  function useTrackProgress (line 174) | function useTrackProgress(trackId: string): TrackProgress {
  function useIsCurrentTrack (line 182) | function useIsCurrentTrack(trackId: string): boolean {
  function useTrackQueuePosition (line 190) | function useTrackQueuePosition(trackId: string): number | null {
  function useTrackPlayer (line 199) | function useTrackPlayer(track: Track) {
  function useVolumeControl (line 250) | function useVolumeControl() {
  function useQueue (line 285) | function useQueue() {
  function useQueueControls (line 310) | function useQueueControls() {
  function usePlayerQueue (line 329) | function usePlayerQueue() {
  function usePlaybackModes (line 346) | function usePlaybackModes() {
  function usePlayer (line 391) | function usePlayer() {
  function useTrackNavigation (line 418) | function useTrackNavigation() {
  function usePlayerKeyboardControls (line 461) | function usePlayerKeyboardControls(enabled = true) {

FILE: apps/rtk-query/src/player/playerMiddleware.ts
  function setupAudioEventListeners (line 110) | function setupAudioEventListeners(store: any) {

FILE: apps/rtk-query/src/player/types/player.types.ts
  type Track (line 1) | interface Track {
  type Playlist (line 13) | interface Playlist {
  type PlaybackState (line 23) | type PlaybackState = 'idle' | 'playing' | 'paused' | 'loading' | 'error'
  type RepeatMode (line 25) | type RepeatMode = 'off' | 'one' | 'all'
  type PlayerState (line 27) | interface PlayerState {
  type TrackPlaybackState (line 63) | interface TrackPlaybackState {
  type TrackProgress (line 70) | interface TrackProgress {
  type FormattedTime (line 75) | interface FormattedTime {

FILE: apps/rtk-query/src/player/utils/convert-api-track-to-player-track.ts
  type AnyTrack (line 7) | type AnyTrack = TrackDetails<BaseAttributes & { user?: { id: string; nam...

FILE: apps/rtk-query/src/player/utils/format-time.ts
  function formatTime (line 4) | function formatTime(seconds: number): string {
  function padZero (line 23) | function padZero(num: number): string {
  function parseTime (line 30) | function parseTime(timeString: string): number {

FILE: apps/rtk-query/src/player/utils/shuffle.ts
  function shuffle (line 5) | function shuffle<T>(array: T[]): T[] {
  function shuffleWithCurrentItem (line 20) | function shuffleWithCurrentItem<T>(array: T[], currentIndex: number): T[] {

FILE: apps/rtk-query/src/player/utils/throttle.ts
  function throttle (line 4) | function throttle<T extends (...args: any[]) => any>(
  function debounce (line 33) | function debounce<T extends (...args: any[]) => any>(

FILE: apps/rtk-query/src/shared/components/AudioPlayer/AudioPlayer.tsx
  type PlayerProps (line 22) | type PlayerProps = {

FILE: apps/rtk-query/src/shared/components/AudioPlayer/AudioPlayerSceleton/AudioPlayerSkeleton.stories.tsx
  type Story (line 12) | type Story = StoryObj<typeof AudioPlayerSkeleton>

FILE: apps/rtk-query/src/shared/components/Autocomplete/Autocomplete.stories.tsx
  type Story (line 20) | type Story = StoryObj<typeof meta>

FILE: apps/rtk-query/src/shared/components/Autocomplete/Autocomplete.tsx
  type AutocompleteOption (line 26) | type AutocompleteOption = {
  type AutocompleteProps (line 32) | type AutocompleteProps = {
  type AutocompleteDropdownPortalProps (line 398) | type AutocompleteDropdownPortalProps = {

FILE: apps/rtk-query/src/shared/components/Avatar/Avatar.stories.tsx
  type Story (line 15) | type Story = StoryObj<typeof meta>

FILE: apps/rtk-query/src/shared/components/Avatar/Avatar.tsx
  type DefaultAvatarProps (line 8) | type DefaultAvatarProps = {

FILE: apps/rtk-query/src/shared/components/Button/Button.stories.tsx
  type Story (line 15) | type Story = StoryObj<typeof meta>

FILE: apps/rtk-query/src/shared/components/Button/Button.tsx
  type ButtonVariant (line 6) | type ButtonVariant = 'primary' | 'secondary'
  type ButtonProps (line 8) | type ButtonProps<T extends ElementType = 'button'> = {

FILE: apps/rtk-query/src/shared/components/Card/Card.stories.tsx
  type Story (line 17) | type Story = StoryObj<typeof meta>

FILE: apps/rtk-query/src/shared/components/Card/Card.tsx
  type CardProps (line 6) | type CardProps<T extends ElementType = 'div'> = {

FILE: apps/rtk-query/src/shared/components/Dialog/Dialog.tsx
  type DialogContextType (line 8) | type DialogContextType = {
  type DialogProps (line 22) | type DialogProps = {
  type DialogHeaderProps (line 70) | type DialogHeaderProps = {
  type DialogContentProps (line 99) | type DialogContentProps = {
  type DialogFooterProps (line 112) | type DialogFooterProps = {

FILE: apps/rtk-query/src/shared/components/DropdownMenu/DropdownMenu.stories.tsx
  type Story (line 24) | type Story = StoryObj<typeof meta>

FILE: apps/rtk-query/src/shared/components/DropdownMenu/DropdownMenu.tsx
  type DropdownMenuProps (line 11) | type DropdownMenuProps = {
  type DropdownMenuTriggerProps (line 28) | type DropdownMenuTriggerProps = {
  type DropdownMenuContentProps (line 63) | type DropdownMenuContentProps = {
  type DropdownMenuItemProps (line 90) | type DropdownMenuItemProps<T extends ElementType = 'button'> = {
  type DropdownMenuSeparatorProps (line 130) | type DropdownMenuSeparatorProps = {

FILE: apps/rtk-query/src/shared/components/FileUploader/FileUploader.tsx
  type FileUploaderProps (line 10) | type FileUploaderProps = {

FILE: apps/rtk-query/src/shared/components/FormControlledTextField/FormControlledTextField.tsx
  type FormControlledTextFieldProps (line 5) | type FormControlledTextFieldProps<T extends FieldValues> = {

FILE: apps/rtk-query/src/shared/components/Hashtag/Tag.stories.tsx
  type Story (line 17) | type Story = StoryObj<typeof meta>

FILE: apps/rtk-query/src/shared/components/Hashtag/Tag.tsx
  type HashtagProps (line 6) | type HashtagProps<T extends ElementType = 'button'> = {

FILE: apps/rtk-query/src/shared/components/IconButton/IconButton.stories.tsx
  type Story (line 25) | type Story = StoryObj<typeof meta>

FILE: apps/rtk-query/src/shared/components/IconButton/IconButton.tsx
  type IconButtonProps (line 6) | type IconButtonProps = {

FILE: apps/rtk-query/src/shared/components/ImageCropper/ImageCropper.stories.tsx
  type Story (line 20) | type Story = StoryObj<typeof meta>

FILE: apps/rtk-query/src/shared/components/ImageCropper/ImageCropper.tsx
  type CropShape (line 11) | type CropShape = 'rect' | 'round'
  type ImageCropperProps (line 13) | type ImageCropperProps = {

FILE: apps/rtk-query/src/shared/components/ImageUploader/ImageUploader.stories.tsx
  type Story (line 21) | type Story = StoryObj<typeof meta>

FILE: apps/rtk-query/src/shared/components/ImageUploader/ImageUploader.tsx
  type ImageUploaderProps (line 12) | type ImageUploaderProps = {
  constant MAX_SIZE_IN_MB (line 25) | const MAX_SIZE_IN_MB = 5
  constant ACCEPTED_FORMATS (line 26) | const ACCEPTED_FORMATS = ['image/jpeg', 'image/jpg', 'image/png', 'image...

FILE: apps/rtk-query/src/shared/components/Loader/Loader.tsx
  type LoaderProps (line 5) | type LoaderProps = ComponentProps<'progress'>

FILE: apps/rtk-query/src/shared/components/Pagination/Pagination.stories.tsx
  type Story (line 18) | type Story = StoryObj<typeof meta>

FILE: apps/rtk-query/src/shared/components/Pagination/Pagination.tsx
  type PaginationProps (line 9) | type PaginationProps = {
  constant MAX_VISIBLE_PAGES (line 17) | const MAX_VISIBLE_PAGES = 5

FILE: apps/rtk-query/src/shared/components/Progress/Progress.stories.tsx
  type Story (line 19) | type Story = StoryObj<typeof meta>

FILE: apps/rtk-query/src/shared/components/Progress/Progress.tsx
  type ProgressProps (line 6) | type ProgressProps = {

FILE: apps/rtk-query/src/shared/components/ReactionButtons/ReactionButtons.stories.tsx
  type Story (line 18) | type Story = StoryObj<typeof meta>

FILE: apps/rtk-query/src/shared/components/ReactionButtons/ReactionButtons.tsx
  type CurrentUserReaction (line 9) | enum CurrentUserReaction {
  type ReactionButtonsProps (line 15) | type ReactionButtonsProps = {
  constant SIZE_MAP (line 25) | const SIZE_MAP = {
  type ReactionButtonsSize (line 30) | type ReactionButtonsSize = keyof typeof SIZE_MAP

FILE: apps/rtk-query/src/shared/components/SearchField/SearchField.stories.tsx
  type Story (line 15) | type Story = StoryObj<typeof meta>

FILE: apps/rtk-query/src/shared/components/SearchField/SearchField.tsx
  type SearchFieldProps (line 8) | type SearchFieldProps = {

FILE: apps/rtk-query/src/shared/components/Select/Select.stories.tsx
  type Story (line 16) | type Story = StoryObj<typeof meta>

FILE: apps/rtk-query/src/shared/components/Select/Select.tsx
  type SelectOption (line 10) | type SelectOption = {
  type SelectProps (line 16) | type SelectProps = {

FILE: apps/rtk-query/src/shared/components/Skeleton/Skeleton.stories.tsx
  type Story (line 17) | type Story = StoryObj<typeof meta>

FILE: apps/rtk-query/src/shared/components/Skeleton/Skeleton.tsx
  type SkeletonProps (line 6) | type SkeletonProps = {

FILE: apps/rtk-query/src/shared/components/SortSelect/Select.tsx
  type SelectOption (line 10) | type SelectOption = {
  type SelectProps (line 16) | type SelectProps = {

FILE: apps/rtk-query/src/shared/components/Spinner/Spinner.stories.tsx
  type Story (line 20) | type Story = StoryObj<typeof meta>

FILE: apps/rtk-query/src/shared/components/Spinner/Spinner.tsx
  type SpinnerProps (line 5) | type SpinnerProps = {

FILE: apps/rtk-query/src/shared/components/Table/Table.stories.tsx
  type Story (line 18) | type Story = StoryObj<typeof meta>

FILE: apps/rtk-query/src/shared/components/Table/Table.tsx
  type TableProps (line 10) | type TableProps = {
  type TableHeadProps (line 27) | type TableHeadProps = {
  type TableBodyProps (line 44) | type TableBodyProps = {
  type TableRowProps (line 61) | type TableRowProps = {
  type TableHeaderCellProps (line 78) | type TableHeaderCellProps = {
  type TableCellProps (line 95) | type TableCellProps = {

FILE: apps/rtk-query/src/shared/components/Tabs/Tabs.tsx
  type TabsContextType (line 6) | type TabsContextType = {
  type TabsProps (line 25) | type TabsProps = {
  type TabsListProps (line 63) | type TabsListProps = {
  type TabsTriggerProps (line 76) | type TabsTriggerProps = {
  type TabsContentProps (line 108) | type TabsContentProps = {

FILE: apps/rtk-query/src/shared/components/TagEditor/TagEditor.tsx
  type TagEditorProps (line 12) | type TagEditorProps = {

FILE: apps/rtk-query/src/shared/components/TextField/TextField.stories.tsx
  type Story (line 17) | type Story = StoryObj<typeof meta>

FILE: apps/rtk-query/src/shared/components/TextField/TextField.tsx
  type TextFieldSize (line 8) | type TextFieldSize = 'm' | 'l'
  type TextFieldProps (line 10) | type TextFieldProps = {

FILE: apps/rtk-query/src/shared/components/Textarea/Textarea.stories.tsx
  type Story (line 15) | type Story = StoryObj<typeof meta>

FILE: apps/rtk-query/src/shared/components/Textarea/Textarea.tsx
  type TextareaProps (line 8) | type TextareaProps = {

FILE: apps/rtk-query/src/shared/components/Typography/Typography.stories.tsx
  type Story (line 15) | type Story = StoryObj<typeof meta>

FILE: apps/rtk-query/src/shared/components/Typography/Typography.tsx
  constant VARIANT_DEFAULT_COMPONENT (line 7) | const VARIANT_DEFAULT_COMPONENT: Record<string, ElementType> = {
  type TypographyVariant (line 18) | type TypographyVariant =
  type Props (line 29) | type Props<T extends ElementType> = {

FILE: apps/rtk-query/src/shared/constants/constants.ts
  constant LOCALE_KEY (line 1) | const LOCALE_KEY = 'locale'
  constant TRACK_SKELETON_INFO_LINES (line 4) | const TRACK_SKELETON_INFO_LINES = 3
  constant TRACK_SKELETON_PLAYLISTS (line 5) | const TRACK_SKELETON_PLAYLISTS = 2
  constant PLAYLIST_SKELETON_INFO_LINES (line 6) | const PLAYLIST_SKELETON_INFO_LINES = 4
  constant PLAYLIST_SKELETON_TABLE_ROWS (line 7) | const PLAYLIST_SKELETON_TABLE_ROWS = 3
  constant USER_TABS_SKELETON_PLAYLISTS (line 8) | const USER_TABS_SKELETON_PLAYLISTS = 5

FILE: apps/rtk-query/src/shared/hooks/useDebounce.ts
  function useDebounce (line 6) | function useDebounce<T>(value: T, delay?: number): T {

FILE: apps/rtk-query/src/shared/hooks/useHover.ts
  function useHover (line 3) | function useHover<T extends HTMLElement>(): [RefObject<T | null>, boolea...

FILE: apps/rtk-query/src/shared/types/common.types.ts
  type Nullable (line 1) | type Nullable<T> = T | null

FILE: apps/rtk-query/src/shared/types/commonApi.types.ts
  type ExtensionsError (line 1) | type ExtensionsError = {
  type Images (line 7) | type Images = {
  type Meta (line 11) | type Meta = {
  type Cover (line 20) | type Cover = {
  type ImageType (line 28) | enum ImageType {
  type CurrentUserReaction (line 34) | enum CurrentUserReaction {
  type User (line 40) | type User = {
  type ReactionResponse (line 45) | type ReactionResponse = {

FILE: apps/rtk-query/src/shared/utils/build-query-string.ts
  type QueryParamValue (line 1) | type QueryParamValue = string | number | (string | number)[] | undefined...
  function buildQueryString (line 18) | function buildQueryString(params: Record<string, QueryParamValue>): stri...

FILE: apps/rtk-query/src/shared/utils/set-locale.ts
  type Locale (line 5) | type Locale = 'en' | 'ru'

FILE: apps/tanstack-query-zustand/src/App.tsx
  function App (line 6) | function App() {

FILE: apps/tanstack-query-zustand/src/app/entrypoint/main.tsx
  type MutationMeta (line 24) | type MutationMeta = {
  type Register (line 33) | interface Register {

FILE: apps/tanstack-query-zustand/src/entities/playlist/ui/PlaylistCard/PlaylistCard.stories.tsx
  type Story (line 14) | type Story = StoryObj<typeof PlaylistCard>

FILE: apps/tanstack-query-zustand/src/entities/playlist/ui/PlaylistCard/PlaylistCard.tsx
  type PlaylistCardProps (line 23) | interface PlaylistCardProps {

FILE: apps/tanstack-query-zustand/src/entities/playlist/ui/PlaylistCardSkeleton/PlaylistCardSkeleton.tsx
  type PlaylistCardSkeletonProps (line 8) | type PlaylistCardSkeletonProps = {

FILE: apps/tanstack-query-zustand/src/entities/playlist/ui/PlaylistItem/PlaylistItem.types.ts
  type CurrentUserReaction (line 4) | type CurrentUserReaction = components['schemas']['ReactionValue']
  type PlaylistItemProps (line 6) | interface PlaylistItemProps {

FILE: apps/tanstack-query-zustand/src/features/artists/api/artists-api.ts
  constant MOCK_ARTISTS (line 1) | const MOCK_ARTISTS = [

FILE: apps/tanstack-query-zustand/src/features/artists/api/use-artists.query.ts
  type ArtistDto (line 5) | type ArtistDto = {

FILE: apps/tanstack-query-zustand/src/features/artists/ui/ArtistCard/ArtistCard.stories.tsx
  type Story (line 12) | type Story = StoryObj<typeof ArtistCard>

FILE: apps/tanstack-query-zustand/src/features/artists/ui/ArtistCard/ArtistCard.tsx
  type Props (line 5) | type Props = {

FILE: apps/tanstack-query-zustand/src/features/auth/types/auth-api.types.ts
  type RefreshOutput (line 4) | type RefreshOutput = components['schemas']['RefreshOutput']
  type RefreshRequestPayload (line 6) | type RefreshRequestPayload = components['schemas']['RefreshRequestPayload']
  type LoginRequestPayload (line 8) | type LoginRequestPayload = components['schemas']['LoginRequestPayload']

FILE: apps/tanstack-query-zustand/src/features/auth/ui/LoginModal/LoginModal.tsx
  type Props (line 11) | type Props = {

FILE: apps/tanstack-query-zustand/src/features/auth/ui/ProfileDropdownMenu/ProfileDropdownMenu.stories.tsx
  type Story (line 15) | type Story = StoryObj<typeof ProfileDropdownMenu>

FILE: apps/tanstack-query-zustand/src/features/auth/ui/ProfileDropdownMenu/ProfileDropdownMenu.tsx
  type ProfileDropdownMenuProps (line 18) | type ProfileDropdownMenuProps = {

FILE: apps/tanstack-query-zustand/src/features/playlists/api/playlistsApi.ts
  constant MOCK_PLAYLISTS (line 39) | const MOCK_PLAYLISTS: SchemaGetPlaylistOutput[] = [
  constant MOCK_PLAYLIST (line 376) | const MOCK_PLAYLIST: SchemaGetPlaylistOutput = {

FILE: apps/tanstack-query-zustand/src/features/playlists/api/types.ts
  type CurrentUserReaction (line 1) | enum CurrentUserReaction {

FILE: apps/tanstack-query-zustand/src/features/playlists/ui/ChoosePlaylistModal/ChoosePlaylistModal.tsx
  function handleToggle (line 43) | function handleToggle(id: string) {

FILE: apps/tanstack-query-zustand/src/features/playlists/ui/PlaylistOverview/PlaylistOverview.stories.tsx
  constant MOCK_TAGS (line 7) | const MOCK_TAGS = MOCK_5_HASHTAGS.map((name, index) => ({ id: String(ind...
  type Story (line 16) | type Story = StoryObj<typeof PlaylistOverview>

FILE: apps/tanstack-query-zustand/src/features/playlists/ui/PlaylistOverview/PlaylistOverview.tsx
  type PlaylistOverviewProps (line 11) | type PlaylistOverviewProps = {

FILE: apps/tanstack-query-zustand/src/features/playlists/ui/PlaylistRow/PlaylistRow.tsx
  type PlaylistRowProps (line 10) | type PlaylistRowProps = {

FILE: apps/tanstack-query-zustand/src/features/profile/model/profile-schemas.ts
  type ValidateField (line 3) | type ValidateField = (value: string) => true | string

FILE: apps/tanstack-query-zustand/src/features/profile/model/profile-store.ts
  type ProfileStore (line 9) | type ProfileStore = {

FILE: apps/tanstack-query-zustand/src/features/profile/types/profile.types.ts
  type FullName (line 1) | type FullName = {
  type Profile (line 6) | type Profile = {

FILE: apps/tanstack-query-zustand/src/features/profile/ui/EditProfileModal/EditProfileModal.tsx
  type FormData (line 24) | type FormData = {

FILE: apps/tanstack-query-zustand/src/features/profile/utils/profile-storage.ts
  method getProfile (line 5) | getProfile(userId: string): Profile | null {
  method saveProfile (line 16) | saveProfile(userId: string, profile: Profile) {

FILE: apps/tanstack-query-zustand/src/features/tags/api/tags-api.ts
  constant MOCK_HASHTAGS (line 1) | const MOCK_HASHTAGS = [
  constant MOCK_5_HASHTAGS (line 13) | const MOCK_5_HASHTAGS = MOCK_HASHTAGS.slice(0, 5)
  type TagDto (line 15) | type TagDto = {

FILE: apps/tanstack-query-zustand/src/features/tags/ui/TagsList/TagsList.stories.tsx
  type Story (line 13) | type Story = StoryObj<typeof TagsList>

FILE: apps/tanstack-query-zustand/src/features/tracks/api/tracksApi.ts
  constant MOCK_TRACKS (line 44) | const MOCK_TRACKS = [

FILE: apps/tanstack-query-zustand/src/features/tracks/api/types.ts
  type CurrentUserReaction (line 1) | enum CurrentUserReaction {

FILE: apps/tanstack-query-zustand/src/features/tracks/ui/CreateTrackForm/CreateTrackModal.tsx
  type UploadTrackData (line 24) | type UploadTrackData = {

FILE: apps/tanstack-query-zustand/src/features/tracks/ui/TrackActions/TrackActions.tsx
  type TrackActionsProps (line 18) | type TrackActionsProps = {

FILE: apps/tanstack-query-zustand/src/features/tracks/ui/TrackActionsMenu/TrackActionsMenu.tsx
  type TrackActionsMenuProps (line 20) | type TrackActionsMenuProps = {

FILE: apps/tanstack-query-zustand/src/features/tracks/ui/TrackCard/TrackCard.stories.tsx
  type Story (line 12) | type Story = StoryObj<typeof TrackCard>

FILE: apps/tanstack-query-zustand/src/features/tracks/ui/TrackCard/TrackCard.tsx
  type Props (line 16) | type Props = {

FILE: apps/tanstack-query-zustand/src/features/tracks/ui/TrackOverview/TrackOverview.stories.tsx
  constant MOCK_TAGS (line 7) | const MOCK_TAGS = MOCK_5_HASHTAGS.map((name, index) => ({ id: String(ind...
  type Story (line 16) | type Story = StoryObj<typeof TrackOverview>

FILE: apps/tanstack-query-zustand/src/features/tracks/ui/TrackOverview/TrackOverview.tsx
  type TrackOverviewProps (line 11) | type TrackOverviewProps = {

FILE: apps/tanstack-query-zustand/src/features/tracks/ui/TrackRowContainer/TrackRowContainer.tsx
  type TrackRowContainerProps (line 7) | interface TrackRowContainerProps {

FILE: apps/tanstack-query-zustand/src/features/tracks/ui/TracksTable/TrackTable.stories.tsx
  type Story (line 24) | type Story = StoryObj<typeof TracksTable>
  type ReactionsProps (line 26) | type ReactionsProps =
  type TrackRowData (line 38) | type TrackRowData = {

FILE: apps/tanstack-query-zustand/src/features/tracks/ui/TracksTable/TracksTable.tsx
  type TableColumn (line 15) | type TableColumn = {
  type TracksTableProps (line 20) | type TracksTableProps<T extends TrackRowData> = {
  type ReactionsProps (line 25) | type ReactionsProps =
  type TrackRowData (line 37) | type TrackRowData = {

FILE: apps/tanstack-query-zustand/src/features/tracks/ui/TracksTableSkeleton/TracksTableSkeleton.tsx
  type Props (line 5) | type Props = {

FILE: apps/tanstack-query-zustand/src/features/tracks/utils/playlistSync.ts
  type PlaylistSyncParams (line 1) | type PlaylistSyncParams = {

FILE: apps/tanstack-query-zustand/src/layout/Sidebar/MenuLinks/MenuLinks.tsx
  type MenuLink (line 17) | type MenuLink = {
  type MenuButton (line 23) | type MenuButton = {

FILE: apps/tanstack-query-zustand/src/pages/MainPage/MainPage.tsx
  type PlaylistListItem (line 31) | type PlaylistListItem = components['schemas']['PlaylistListItemResource']
  constant NEW_TRACKS_PLAYLIST_ID (line 33) | const NEW_TRACKS_PLAYLIST_ID = 'new-tracks'
  type TrackMainPageCardProps (line 63) | type TrackMainPageCardProps = {

FILE: apps/tanstack-query-zustand/src/pages/PlaylistPage/ui/ControlPanel/ControlPanel.tsx
  type ControlPanelProps (line 16) | type ControlPanelProps = {

FILE: apps/tanstack-query-zustand/src/pages/PlaylistPage/ui/PlaylistPageSkeleton/PlaylistPageSkeleton.tsx
  constant INFO_LINES (line 9) | const INFO_LINES = 3
  constant TABLE_ROWS (line 10) | const TABLE_ROWS = 5

FILE: apps/tanstack-query-zustand/src/pages/PlaylistsPage/PlaylistsPage.tsx
  constant PAGE_SIZE (line 20) | const PAGE_SIZE = 5

FILE: apps/tanstack-query-zustand/src/pages/PlaylistsPage/PlaylistsPage.types.ts
  type SortOption (line 3) | type SortOption = 'mostLiked' | 'leastLiked' | 'newest' | 'oldest'
  type ISortConfig (line 5) | interface ISortConfig {

FILE: apps/tanstack-query-zustand/src/pages/PlaylistsPage/model/useCreatePlaylist.ts
  function useCreatePlaylist (line 6) | function useCreatePlaylist() {

FILE: apps/tanstack-query-zustand/src/pages/PlaylistsPage/model/useDeletePlaylist.ts
  function useDeletePlaylist (line 6) | function useDeletePlaylist() {

FILE: apps/tanstack-query-zustand/src/pages/PlaylistsPage/model/useUploadPlaylistCover.ts
  function useUploadPlaylistCover (line 7) | function useUploadPlaylistCover() {

FILE: apps/tanstack-query-zustand/src/pages/TrackPage/ui/ControlPanel/ControlPanel.tsx
  type ControlPanelProps (line 12) | type ControlPanelProps = {

FILE: apps/tanstack-query-zustand/src/pages/TrackPage/ui/TrackPageSkeleton/TrackPageSkeleton.tsx
  constant INFO_LINES (line 8) | const INFO_LINES = 3
  constant PLAYLIST_ROWS (line 9) | const PLAYLIST_ROWS = 4

FILE: apps/tanstack-query-zustand/src/pages/TracksPage/TracksPage.tsx
  constant PAGE_SIZE (line 31) | const PAGE_SIZE = 10

FILE: apps/tanstack-query-zustand/src/pages/TracksPage/model/useTrackDetails.ts
  function useTrackDetails (line 6) | function useTrackDetails(trackId: string) {

FILE: apps/tanstack-query-zustand/src/pages/TracksPage/model/useTracksInfinityQuery.ts
  type TracksParams (line 12) | type TracksParams = Partial<SchemaGetTracksRequestPayload>
  function useTracksInfinityQuery (line 14) | function useTracksInfinityQuery<P extends TracksParams>(

FILE: apps/tanstack-query-zustand/src/pages/TracksPage/model/useTracksQuery.tsx
  type TracksParams (line 9) | type TracksParams = Partial<SchemaGetTracksRequestPayload>
  function useTracksQuery (line 11) | function useTracksQuery<P extends TracksParams>(params: Strict<TracksPar...

FILE: apps/tanstack-query-zustand/src/pages/TracksPage/tracksPageTypes/TracksPageTypes.ts
  type SortField (line 6) | type SortField = PathsPlaylistsTracksGetParametersQuerySortBy
  type SortOrder (line 7) | type SortOrder = PathsPlaylistsGetParametersQuerySortDirection
  type SortTracksParams (line 9) | type SortTracksParams = {

FILE: apps/tanstack-query-zustand/src/pages/UserPage/ui/UserInfo/UserStats.tsx
  type UserStatsProps (line 7) | type UserStatsProps = {

FILE: apps/tanstack-query-zustand/src/pages/UserPage/ui/UserTabs/LikedTracksTab/LikedTracksTab.tsx
  constant PAGE_SIZE (line 26) | const PAGE_SIZE = 5
  constant DEFAULT_PAGE (line 27) | const DEFAULT_PAGE = 1

FILE: apps/tanstack-query-zustand/src/pages/UserPage/ui/UserTabs/MyLikedPlaylistsTab/MyLikedPlaylistsTab.tsx
  constant PAGE_SIZE (line 17) | const PAGE_SIZE = 5
  constant DEFAULT_PAGE (line 18) | const DEFAULT_PAGE = 1
  type PlaylistListItem (line 19) | type PlaylistListItem = components['schemas']['PlaylistListItemResource']

FILE: apps/tanstack-query-zustand/src/pages/UserPage/ui/UserTabs/PlaylistsTab/PlaylistsTab.tsx
  constant PAGE_SIZE (line 19) | const PAGE_SIZE = 8
  constant DEFAULT_PAGE (line 20) | const DEFAULT_PAGE = 1

FILE: apps/tanstack-query-zustand/src/pages/UserPage/ui/UserTabs/TracksTab/TracksTab.tsx
  constant PAGE_SIZE (line 26) | const PAGE_SIZE = 5
  constant DEFAULT_PAGE (line 27) | const DEFAULT_PAGE = 1

FILE: apps/tanstack-query-zustand/src/pages/common/ContentList/ContentList.tsx
  type ContentListProps (line 7) | type ContentListProps<T> = {
  constant SKELETON_ITEM_COUNT (line 18) | const SKELETON_ITEM_COUNT = 10

FILE: apps/tanstack-query-zustand/src/pages/common/PageWithHeader/PageWithHeader.tsx
  type PageWithHeaderProps (line 5) | type PageWithHeaderProps = {

FILE: apps/tanstack-query-zustand/src/pages/common/PageWithoutHeader/PageWithoutHeader.tsx
  type PageWithoutHeaderProps (line 5) | type PageWithoutHeaderProps = {

FILE: apps/tanstack-query-zustand/src/pages/common/PageWrapper/PageWrapper.tsx
  type PageWrapperProps (line 5) | type PageWrapperProps = {

FILE: apps/tanstack-query-zustand/src/player/model/audio-manager.ts
  type AudioEventMap (line 3) | type AudioEventMap = {
  type EventCallback (line 14) | type EventCallback<K extends keyof AudioEventMap> = (data: AudioEventMap...
  class AudioManager (line 16) | class AudioManager {
    method constructor (line 22) | private constructor() {
    method get (line 30) | static get(): AudioManager {
    method bindEvents (line 37) | private bindEvents() {
    method on (line 77) | on<K extends keyof AudioEventMap>(event: K, callback: EventCallback<K>) {
    method off (line 84) | off<K extends keyof AudioEventMap>(event: K, callback: EventCallback<K...
    method emit (line 91) | private emit<K extends keyof AudioEventMap>(event: K, data: AudioEvent...
    method loadTrack (line 98) | async loadTrack(track: Track): Promise<void> {
    method play (line 137) | play(): Promise<void> {
    method pause (line 141) | pause() {
    method stop (line 145) | stop() {
    method seek (line 150) | seek(time: number) {
    method setVolume (line 156) | setVolume(volume: number) {
    method setMuted (line 160) | setMuted(muted: boolean) {
    method getCurrentTime (line 164) | getCurrentTime(): number {
    method getDuration (line 168) | getDuration(): number {
    method getPaused (line 172) | getPaused(): boolean {
    method getSrc (line 176) | getSrc(): string {
    method destroy (line 180) | destroy() {

FILE: apps/tanstack-query-zustand/src/player/model/player-hooks.ts
  function usePlayingTrackProgress (line 16) | function usePlayingTrackProgress() {
  function usePlaybackState (line 34) | function usePlaybackState() {
  function useCurrentTrack (line 52) | function useCurrentTrack() {
  function usePlaybackProgress (line 71) | function usePlaybackProgress() {
  function useVolumeControl (line 96) | function useVolumeControl() {
  function useQueue (line 119) | function useQueue() {
  function usePlaybackModes (line 159) | function usePlaybackModes() {
  function useTrackPlayer (line 195) | function useTrackPlayer(track: Track) {
  function usePlayerControls (line 244) | function usePlayerControls() {
  function useQueueControls (line 264) | function useQueueControls() {
  function usePlayerQueue (line 278) | function usePlayerQueue() {
  function usePlayer (line 288) | function usePlayer() {
  function useTrackNavigation (line 308) | function useTrackNavigation() {
  function useSetRepeatMode (line 350) | function useSetRepeatMode() {
  function useCycleRepeatMode (line 356) | function useCycleRepeatMode() {
  function useToggleShuffle (line 365) | function useToggleShuffle() {
  function usePlayerKeyboardControls (line 375) | function usePlayerKeyboardControls(enabled = true) {

FILE: apps/tanstack-query-zustand/src/player/model/player-store.ts
  type PlayerStore (line 82) | type PlayerStore = typeof initialState & {
  method play (line 134) | play(track, playlistId?, tracks?) {
  method pause (line 235) | pause() {
  method resume (line 243) | resume() {
  method stop (line 251) | stop() {
  method togglePlayPause (line 259) | togglePlayPause() {
  method nextTrack (line 276) | nextTrack() {
  method previousTrack (line 348) | previousTrack() {
  method playTrackAtIndex (line 423) | playTrackAtIndex(index) {
  method handleTrackEnded (line 453) | handleTrackEnded() {
  method seek (line 470) | seek(time) {
  method updateTime (line 478) | updateTime(time) {
  method updateBuffered (line 482) | updateBuffered(buffered) {
  method setDuration (line 486) | setDuration(duration) {
  method setVolume (line 494) | setVolume(volume) {
  method toggleMute (line 514) | toggleMute() {
  method setRepeatMode (line 525) | setRepeatMode(mode) {
  method toggleShuffle (line 538) | toggleShuffle() {
  method loadPlaylist (line 577) | loadPlaylist(playlistId, tracks, startIndex = 0) {
  method addToQueue (line 621) | addToQueue(tracks) {
  method insertNext (line 650) | insertNext(track) {
  method removeFromQueue (line 672) | removeFromQueue(index) {
  method clearQueue (line 709) | clearQueue() {
  method setError (line 728) | setError(error) {
  method clearError (line 735) | clearError() {
  method updateQueueMetadata (line 751) | updateQueueMetadata() {
  function setupAudioListeners (line 791) | function setupAudioListeners() {
  function initializePlayer (line 844) | function initializePlayer() {
  function cleanupPlayer (line 849) | function cleanupPlayer() {

FILE: apps/tanstack-query-zustand/src/player/model/player-track-hooks.ts
  function useTrackPlaybackState (line 13) | function useTrackPlaybackState(trackId: string): TrackPlaybackState {
  function useTrackProgress (line 31) | function useTrackProgress(trackId: string): TrackProgress {
  function useIsCurrentTrack (line 46) | function useIsCurrentTrack(trackId: string): boolean {
  function useTrackQueuePosition (line 53) | function useTrackQueuePosition(trackId: string): number | null {
  function useIsTrackInQueue (line 63) | function useIsTrackInQueue(trackId: string): boolean {

FILE: apps/tanstack-query-zustand/src/player/types/player.types.ts
  type Track (line 1) | interface Track {
  type Playlist (line 13) | interface Playlist {
  type PlaybackState (line 23) | type PlaybackState = 'idle' | 'playing' | 'paused' | 'loading' | 'error'
  type RepeatMode (line 25) | type RepeatMode = 'off' | 'one' | 'all'
  type PlayerState (line 27) | interface PlayerState {
  type TrackPlaybackState (line 63) | interface TrackPlaybackState {
  type TrackProgress (line 70) | interface TrackProgress {
  type FormattedTime (line 75) | interface FormattedTime {

FILE: apps/tanstack-query-zustand/src/player/utils/format-time.ts
  function formatTime (line 4) | function formatTime(seconds: number): string {
  function padZero (line 23) | function padZero(num: number): string {
  function parseTime (line 30) | function parseTime(timeString: string): number {

FILE: apps/tanstack-query-zustand/src/player/utils/shuffle.ts
  function shuffle (line 5) | function shuffle<T>(array: T[]): T[] {
  function shuffleWithCurrentItem (line 20) | function shuffleWithCurrentItem<T>(array: T[], currentIndex: number): T[] {

FILE: apps/tanstack-query-zustand/src/player/utils/track-navigation.ts
  function getNextTrackId (line 6) | function getNextTrackId(
  function getPreviousTrackId (line 27) | function getPreviousTrackId(
  function getQueuePosition (line 47) | function getQueuePosition(queueIndex: number, queueLength: number) {

FILE: apps/tanstack-query-zustand/src/shared/api/client.ts
  function makeRefreshToken (line 28) | function makeRefreshToken(): Promise<string> {
  method onRequest (line 60) | async onRequest({ request }) {
  method onResponse (line 69) | async onResponse({ request, response }) {
  constant LOCAL_HOSTNAMES (line 106) | const LOCAL_HOSTNAMES = new Set(['localhost', '127.0.0.1', '::1', '0.0.0...
  function isLocalClient (line 108) | function isLocalClient(): boolean {
  function assertApiConfig (line 114) | function assertApiConfig() {

FILE: apps/tanstack-query-zustand/src/shared/api/schema.ts
  type paths (line 6) | interface paths {
  type webhooks (line 642) | type webhooks = Record<string, never>
  type components (line 643) | interface components {
  type SchemaUserRef (line 1335) | type SchemaUserRef = components['schemas']['UserRef']
  type SchemaImageVariant (line 1336) | type SchemaImageVariant = components['schemas']['ImageVariant']
  type SchemaPlaylistImagesOutputDto (line 1337) | type SchemaPlaylistImagesOutputDto = components['schemas']['PlaylistImag...
  type SchemaTagRef (line 1338) | type SchemaTagRef = components['schemas']['TagRef']
  type SchemaPlaylistListItemAttributes (line 1339) | type SchemaPlaylistListItemAttributes = components['schemas']['PlaylistL...
  type SchemaPlaylistListItemResource (line 1340) | type SchemaPlaylistListItemResource = components['schemas']['PlaylistLis...
  type SchemaGetMyPlaylistsOutput (line 1341) | type SchemaGetMyPlaylistsOutput = components['schemas']['GetMyPlaylistsO...
  type SchemaCreatePlaylistAttributes (line 1342) | type SchemaCreatePlaylistAttributes = components['schemas']['CreatePlayl...
  type SchemaCreatePlaylistData (line 1343) | type SchemaCreatePlaylistData = components['schemas']['CreatePlaylistData']
  type SchemaCreatePlaylistRequestPayload (line 1344) | type SchemaCreatePlaylistRequestPayload =
  type SchemaPlaylistAttributes (line 1346) | type SchemaPlaylistAttributes = components['schemas']['PlaylistAttributes']
  type SchemaPlaylistResource (line 1347) | type SchemaPlaylistResource = components['schemas']['PlaylistResource']
  type SchemaGetPlaylistOutput (line 1348) | type SchemaGetPlaylistOutput = components['schemas']['GetPlaylistOutput']
  type SchemaUpdatePlaylistAttributes (line 1349) | type SchemaUpdatePlaylistAttributes = components['schemas']['UpdatePlayl...
  type SchemaUpdatePlaylistData (line 1350) | type SchemaUpdatePlaylistData = components['schemas']['UpdatePlaylistData']
  type SchemaUpdatePlaylistRequestPayload (line 1351) | type SchemaUpdatePlaylistRequestPayload =
  type SchemaReorderPlaylistsRequestPayload (line 1353) | type SchemaReorderPlaylistsRequestPayload =
  type SchemaTrackImages (line 1355) | type SchemaTrackImages = components['schemas']['TrackImages']
  type SchemaGetTracksRequestPayload (line 1356) | type SchemaGetTracksRequestPayload = components['schemas']['GetTracksReq...
  type SchemaJsonApiErrorSource (line 1357) | type SchemaJsonApiErrorSource = components['schemas']['JsonApiErrorSource']
  type SchemaJsonApiError (line 1358) | type SchemaJsonApiError = components['schemas']['JsonApiError']
  type SchemaJsonApiErrorDocument (line 1359) | type SchemaJsonApiErrorDocument = components['schemas']['JsonApiErrorDoc...
  type SchemaTrackAttachment (line 1360) | type SchemaTrackAttachment = components['schemas']['TrackAttachment']
  type SchemaTrackListItemAttributes (line 1361) | type SchemaTrackListItemAttributes = components['schemas']['TrackListIte...
  type SchemaArtistRelationship (line 1362) | type SchemaArtistRelationship = components['schemas']['ArtistRelationship']
  type SchemaArtistsRelationship (line 1363) | type SchemaArtistsRelationship = components['schemas']['ArtistsRelations...
  type SchemaTrackRelationships (line 1364) | type SchemaTrackRelationships = components['schemas']['TrackRelationships']
  type SchemaTrackListItemResource (line 1365) | type SchemaTrackListItemResource = components['schemas']['TrackListItemR...
  type SchemaJsonApiMetaWithPagingAndCursor (line 1366) | type SchemaJsonApiMetaWithPagingAndCursor =
  type SchemaOmitTypeClass (line 1368) | type SchemaOmitTypeClass = components['schemas']['OmitTypeClass']
  type SchemaIncludedArtistOutput (line 1369) | type SchemaIncludedArtistOutput = components['schemas']['IncludedArtistO...
  type SchemaGetTrackListOutput (line 1370) | type SchemaGetTrackListOutput = components['schemas']['GetTrackListOutput']
  type SchemaGetTracksCountOutput (line 1371) | type SchemaGetTracksCountOutput = components['schemas']['GetTracksCountO...
  type SchemaTrackListItemAttributesForPlaylist (line 1372) | type SchemaTrackListItemAttributesForPlaylist =
  type SchemaTrackListItemResourceForPlaylist (line 1374) | type SchemaTrackListItemResourceForPlaylist =
  type SchemaJsonApiMeta (line 1376) | type SchemaJsonApiMeta = components['schemas']['JsonApiMeta']
  type SchemaGetTracksForPlaylistOutput (line 1377) | type SchemaGetTracksForPlaylistOutput = components['schemas']['GetTracks...
  type SchemaArtistRef (line 1378) | type SchemaArtistRef = components['schemas']['ArtistRef']
  type SchemaTrackDetailsAttributes (line 1379) | type SchemaTrackDetailsAttributes = components['schemas']['TrackDetailsA...
  type SchemaTrackDetailsResource (line 1380) | type SchemaTrackDetailsResource = components['schemas']['TrackDetailsRes...
  type SchemaGetTrackDetailsOutput (line 1381) | type SchemaGetTrackDetailsOutput = components['schemas']['GetTrackDetail...
  type SchemaReactionOutput (line 1382) | type SchemaReactionOutput = components['schemas']['ReactionOutput']
  type SchemaGetPlaylistsRequestPayload (line 1383) | type SchemaGetPlaylistsRequestPayload = components['schemas']['GetPlayli...
  type SchemaJsonApiMetaWithPaging (line 1384) | type SchemaJsonApiMetaWithPaging = components['schemas']['JsonApiMetaWit...
  type SchemaGetPlaylistsOutput (line 1385) | type SchemaGetPlaylistsOutput = components['schemas']['GetPlaylistsOutput']
  type SchemaGetPlaylistsCountOutput (line 1386) | type SchemaGetPlaylistsCountOutput = components['schemas']['GetPlaylists...
  type SchemaReorderTracksRequestPayload (line 1387) | type SchemaReorderTracksRequestPayload = components['schemas']['ReorderT...
  type SchemaUpdateTrackAttributes (line 1388) | type SchemaUpdateTrackAttributes = components['schemas']['UpdateTrackAtt...
  type SchemaUpdateTrackData (line 1389) | type SchemaUpdateTrackData = components['schemas']['UpdateTrackData']
  type SchemaUpdateTrackRequestPayload (line 1390) | type SchemaUpdateTrackRequestPayload = components['schemas']['UpdateTrac...
  type SchemaAddTrackToPlaylistAttributes (line 1391) | type SchemaAddTrackToPlaylistAttributes =
  type SchemaAddTrackToPlaylistData (line 1393) | type SchemaAddTrackToPlaylistData = components['schemas']['AddTrackToPla...
  type SchemaAddTrackToPlaylistRequestPayload (line 1394) | type SchemaAddTrackToPlaylistRequestPayload =
  type SchemaCreateArtistAttributes (line 1396) | type SchemaCreateArtistAttributes = components['schemas']['CreateArtistA...
  type SchemaCreateArtistData (line 1397) | type SchemaCreateArtistData = components['schemas']['CreateArtistData']
  type SchemaCreateArtistRequestPayload (line 1398) | type SchemaCreateArtistRequestPayload = components['schemas']['CreateArt...
  type SchemaLoginRequestPayload (line 1399) | type SchemaLoginRequestPayload = components['schemas']['LoginRequestPayl...
  type SchemaRefreshOutput (line 1400) | type SchemaRefreshOutput = components['schemas']['RefreshOutput']
  type SchemaBadRequestException (line 1401) | type SchemaBadRequestException = components['schemas']['BadRequestExcept...
  type SchemaUnauthorizedException (line 1402) | type SchemaUnauthorizedException = components['schemas']['UnauthorizedEx...
  type SchemaRefreshRequestPayload (line 1403) | type SchemaRefreshRequestPayload = components['schemas']['RefreshRequest...
  type SchemaLogoutRequestPayload (line 1404) | type SchemaLogoutRequestPayload = components['schemas']['LogoutRequestPa...
  type SchemaGetMeOutput (line 1405) | type SchemaGetMeOutput = components['schemas']['GetMeOutput']
  type SchemaSimpleLoginRequestPayload (line 1406) | type SchemaSimpleLoginRequestPayload = components['schemas']['SimpleLogi...
  type SchemaSimpleLoginOutput (line 1407) | type SchemaSimpleLoginOutput = components['schemas']['SimpleLoginOutput']
  type SchemaSimpleRefreshRequestPayload (line 1408) | type SchemaSimpleRefreshRequestPayload = components['schemas']['SimpleRe...
  type SchemaSimpleLogoutRequestPayload (line 1409) | type SchemaSimpleLogoutRequestPayload = components['schemas']['SimpleLog...
  type SchemaCreateTagAttributes (line 1410) | type SchemaCreateTagAttributes = components['schemas']['CreateTagAttribu...
  type SchemaCreateTagData (line 1411) | type SchemaCreateTagData = components['schemas']['CreateTagData']
  type SchemaCreateTagRequestPayload (line 1412) | type SchemaCreateTagRequestPayload = components['schemas']['CreateTagReq...
  type SchemaTagAttributes (line 1413) | type SchemaTagAttributes = components['schemas']['TagAttributes']
  type SchemaTagResource (line 1414) | type SchemaTagResource = components['schemas']['TagResource']
  type SchemaGetTagOutput (line 1415) | type SchemaGetTagOutput = components['schemas']['GetTagOutput']
  type SchemaGetTagsOutput (line 1416) | type SchemaGetTagsOutput = components['schemas']['GetTagsOutput']
  type SchemaBinaryFile (line 1417) | type SchemaBinaryFile = components['schemas']['BinaryFile']
  type $defs (line 1418) | type $defs = Record<string, never>
  type operations (line 1419) | interface operations {
  type PathsPlaylistsGetParametersQuerySortBy (line 2964) | enum PathsPlaylistsGetParametersQuerySortBy {
  type PathsPlaylistsGetParametersQuerySortDirection (line 2968) | enum PathsPlaylistsGetParametersQuerySortDirection {
  type PathsPlaylistsTracksGetParametersQuerySortBy (line 2972) | enum PathsPlaylistsTracksGetParametersQuerySortBy {
  type PathsPlaylistsTracksGetParametersQueryPaginationType (line 2976) | enum PathsPlaylistsTracksGetParametersQueryPaginationType {
  type ImageSizeType (line 2980) | enum ImageSizeType {
  type ReactionValue (line 2985) | enum ReactionValue {

FILE: apps/tanstack-query-zustand/src/shared/api/types.ts
  type MainImage (line 3) | type MainImage = components['schemas']['ImageVariant'][]

FILE: apps/tanstack-query-zustand/src/shared/api/utils/json-api-error.ts
  type JsonApiError (line 1) | interface JsonApiError {
  type JsonApiErrorDocument (line 10) | interface JsonApiErrorDocument {
  type ExtractError (line 15) | type ExtractError<T> = T extends { error?: infer E } ? E : unknown
  type JsonApiError (line 18) | interface JsonApiError {
  type JsonApiErrorDocument (line 27) | interface JsonApiErrorDocument {
  function isJsonApiErrorDocument (line 32) | function isJsonApiErrorDocument(error: unknown): error is JsonApiErrorDo...
  function parseJsonApiErrors (line 41) | function parseJsonApiErrors(errorDoc: JsonApiErrorDocument): {

FILE: apps/tanstack-query-zustand/src/shared/api/utils/unwrap.ts
  type ExtractData (line 10) | type ExtractData<T> = T extends { data?: infer D } ? NonNullable<D> : never
  function unwrap (line 12) | async function unwrap<P extends Promise<{ data?: unknown; error?: unknow...

FILE: apps/tanstack-query-zustand/src/shared/components/AudioPlayer/AudioPlayer.tsx
  type PlayerProps (line 28) | type PlayerProps = {

FILE: apps/tanstack-query-zustand/src/shared/components/Autocomplete/Autocomplete.stories.tsx
  type Story (line 20) | type Story = StoryObj<typeof meta>

FILE: apps/tanstack-query-zustand/src/shared/components/Autocomplete/Autocomplete.tsx
  type AutocompleteOption (line 26) | type AutocompleteOption = {
  type AutocompleteProps (line 32) | type AutocompleteProps = {

FILE: apps/tanstack-query-zustand/src/shared/components/Avatar/Avatar.tsx
  type FullName (line 7) | type FullName = {
  type AvatarProps (line 12) | type AvatarProps = {

FILE: apps/tanstack-query-zustand/src/shared/components/Button/Button.stories.tsx
  type Story (line 15) | type Story = StoryObj<typeof meta>

FILE: apps/tanstack-query-zustand/src/shared/components/Button/Button.tsx
  type ButtonVariant (line 6) | type ButtonVariant = 'primary' | 'secondary'
  type ButtonProps (line 8) | type ButtonProps<T extends ElementType = 'button'> = {

FILE: apps/tanstack-query-zustand/src/shared/components/Card/Card.stories.tsx
  type Story (line 17) | type Story = StoryObj<typeof meta>

FILE: apps/tanstack-query-zustand/src/shared/components/Card/Card.tsx
  type CardProps (line 6) | type CardProps<T extends ElementType = 'div'> = {

FILE: apps/tanstack-query-zustand/src/shared/components/CoverImage/CoverImage.tsx
  type Props (line 8) | type Props = {

FILE: apps/tanstack-query-zustand/src/shared/components/Dialog/Dialog.tsx
  type DialogContextType (line 8) | type DialogContextType = {
  type DialogProps (line 22) | type DialogProps = {
  type DialogHeaderProps (line 70) | type DialogHeaderProps = {
  type DialogContentProps (line 99) | type DialogContentProps = {
  type DialogFooterProps (line 112) | type DialogFooterProps = {

FILE: apps/tanstack-query-zustand/src/shared/components/DropdownMenu/DropdownMenu.stories.tsx
  type Story (line 24) | type Story = StoryObj<typeof meta>

FILE: apps/tanstack-query-zustand/src/shared/components/DropdownMenu/DropdownMenu.tsx
  type DropdownMenuContextType (line 16) | type DropdownMenuContextType = {
  type DropdownMenuProps (line 37) | type DropdownMenuProps = {
  type DropdownMenuTriggerProps (line 107) | type DropdownMenuTriggerProps = {
  type DropdownMenuContentProps (line 155) | type DropdownMenuContentProps = {
  type DropdownMenuItemProps (line 243) | type DropdownMenuItemProps<T extends ElementType = 'button'> = {
  type DropdownMenuSeparatorProps (line 286) | type DropdownMenuSeparatorProps = {

FILE: apps/tanstack-query-zustand/src/shared/components/FormControlledTextField/FormControlledTextField.tsx
  type FormControlledTextFieldProps (line 11) | type FormControlledTextFieldProps<T extends FieldValues> = {

FILE: apps/tanstack-query-zustand/src/shared/components/Hashtag/Tag.stories.tsx
  type Story (line 17) | type Story = StoryObj<typeof meta>

FILE: apps/tanstack-query-zustand/src/shared/components/Hashtag/Tag.tsx
  type HashtagProps (line 6) | type HashtagProps<T extends ElementType = 'button'> = {

FILE: apps/tanstack-query-zustand/src/shared/components/IconButton/IconButton.stories.tsx
  type Story (line 25) | type Story = StoryObj<typeof meta>

FILE: apps/tanstack-query-zustand/src/shared/components/IconButton/IconButton.tsx
  type IconButtonProps (line 6) | type IconButtonProps = {

FILE: apps/tanstack-query-zustand/src/shared/components/ImageCropper/ImageCropper.tsx
  type CropShape (line 9) | type CropShape = 'rect' | 'round'
  type Area (line 10) | type Area = {
  type ImageCropperProps (line 17) | type ImageCropperProps = {

FILE: apps/tanstack-query-zustand/src/shared/components/ImageUploader/ImageUploader.stories.tsx
  type Story (line 17) | type Story = StoryObj<typeof meta>

FILE: apps/tanstack-query-zustand/src/shared/components/ImageUploader/ImageUploader.tsx
  type ImageUploaderProps (line 12) | type ImageUploaderProps = {
  constant ACCEPTED_FORMATS (line 26) | const ACCEPTED_FORMATS = ['image/jpeg', 'image/jpg', 'image/png', 'image...

FILE: apps/tanstack-query-zustand/src/shared/components/Pagination/Pagination.stories.tsx
  type Story (line 18) | type Story = StoryObj<typeof meta>

FILE: apps/tanstack-query-zustand/src/shared/components/Pagination/Pagination.tsx
  type PaginationProps (line 9) | type PaginationProps = {
  constant MAX_VISIBLE_PAGES (line 17) | const MAX_VISIBLE_PAGES = 5

FILE: apps/tanstack-query-zustand/src/shared/components/Progress/Progress.stories.tsx
  type Story (line 19) | type Story = StoryObj<typeof meta>

FILE: apps/tanstack-query-zustand/src/shared/components/Progress/Progress.tsx
  type ProgressProps (line 6) | type ProgressProps = {

FILE: apps/tanstack-query-zustand/src/shared/components/ReactionButtons/ReactionButtons.stories.tsx
  type Story (line 20) | type Story = StoryObj<typeof meta>

FILE: apps/tanstack-query-zustand/src/shared/components/ReactionButtons/ReactionButtons.tsx
  type CurrentUserReaction (line 12) | type CurrentUserReaction = ReactionValue
  type ReactionButtonsProps (line 14) | interface ReactionButtonsProps {
  constant SIZE_MAP (line 25) | const SIZE_MAP = {

FILE: apps/tanstack-query-zustand/src/shared/components/SearchField/SearchField.stories.tsx
  type Story (line 15) | type Story = StoryObj<typeof meta>

FILE: apps/tanstack-query-zustand/src/shared/components/SearchField/SearchField.tsx
  type SearchFieldProps (line 8) | type SearchFieldProps = {

FILE: apps/tanstack-query-zustand/src/shared/components/Select/Select.stories.tsx
  type Story (line 16) | type Story = StoryObj<typeof meta>

FILE: apps/tanstack-query-zustand/src/shared/components/Select/Select.tsx
  type SelectOption (line 10) | type SelectOption = {
  type SelectProps (line 16) | type SelectProps = {

FILE: apps/tanstack-query-zustand/src/shared/components/Skeleton/Skeleton.tsx
  type SkeletonProps (line 6) | type SkeletonProps = {

FILE: apps/tanstack-query-zustand/src/shared/components/SortSelect/Select.tsx
  type SelectOption (line 10) | type SelectOption = {
  type SelectProps (line 16) | type SelectProps = {

FILE: apps/tanstack-query-zustand/src/shared/components/Spinner/Spinner.stories.tsx
  type Story (line 20) | type Story = StoryObj<typeof meta>

FILE: apps/tanstack-query-zustand/src/shared/components/Spinner/Spinner.tsx
  type SpinnerProps (line 5) | type SpinnerProps = {

FILE: apps/tanstack-query-zustand/src/shared/components/Table/Table.stories.tsx
  type Story (line 18) | type Story = StoryObj<typeof meta>

FILE: apps/tanstack-query-zustand/src/shared/components/Table/Table.tsx
  type TableProps (line 10) | type TableProps = {
  type TableHeadProps (line 27) | type TableHeadProps = {
  type TableBodyProps (line 44) | type TableBodyProps = {
  type TableRowProps (line 61) | type TableRowProps = {
  type TableHeaderCellProps (line 78) | type TableHeaderCellProps = {
  type TableCellProps (line 95) | type TableCellProps = {

FILE: apps/tanstack-query-zustand/src/shared/components/Tabs/Tabs.tsx
  type TabsContextType (line 6) | type TabsContextType = {
  type TabsProps (line 25) | type TabsProps = {
  type TabsListProps (line 63) | type TabsListProps = {
  type TabsTriggerProps (line 76) | type TabsTriggerProps = {
  type TabsContentProps (line 108) | type TabsContentProps = {

FILE: apps/tanstack-query-zustand/src/shared/components/TagEditor/TagEditor.tsx
  type TagEditorProps (line 13) | type TagEditorProps = {

FILE: apps/tanstack-query-zustand/src/shared/components/TextField/TextField.stories.tsx
  type Story (line 17) | type Story = StoryObj<typeof meta>

FILE: apps/tanstack-query-zustand/src/shared/components/TextField/TextField.tsx
  type TextFieldSize (line 8) | type TextFieldSize = 'm' | 'l'
  type TextFieldProps (line 10) | type TextFieldProps = {

FILE: apps/tanstack-query-zustand/src/shared/components/Textarea/Textarea.stories.tsx
  type Story (line 15) | type Story = StoryObj<typeof meta>

FILE: apps/tanstack-query-zustand/src/shared/components/Textarea/Textarea.tsx
  type TextareaProps (line 8) | type TextareaProps = {

FILE: apps/tanstack-query-zustand/src/shared/components/Typography/Typography.stories.tsx
  type Story (line 15) | type Story = StoryObj<typeof meta>

FILE: apps/tanstack-query-zustand/src/shared/components/Typography/Typography.tsx
  constant VARIANT_DEFAULT_COMPONENT (line 7) | const VARIANT_DEFAULT_COMPONENT: Record<string, ElementType> = {
  type TypographyVariant (line 18) | type TypographyVariant =
  type Props (line 29) | type Props<T extends ElementType> = {

FILE: apps/tanstack-query-zustand/src/shared/config/config.ts
  constant API_BASE_URL (line 1) | const API_BASE_URL = import.meta.env.VITE_API_BASE_URL
  constant API_KEY (line 2) | const API_KEY = import.meta.env.VITE_API_KEY
  constant CURRENT_APP_DOMAIN (line 3) | const CURRENT_APP_DOMAIN = import.meta.env.VITE_APP_BASE_URL

FILE: apps/tanstack-query-zustand/src/shared/hooks/debounceCallback/useDebounceCallback.ts
  function useDebounceCallback (line 37) | function useDebounceCallback<F extends (...args: any[]) => ReturnType<F>>(

FILE: apps/tanstack-query-zustand/src/shared/hooks/debounceCallback/useDebounceCallback.types.ts
  type ControlFunctions (line 1) | interface ControlFunctions {
  type DebouncedState (line 10) | type DebouncedState<F extends (...args: any[]) => ReturnType<F>> = ((

FILE: apps/tanstack-query-zustand/src/shared/hooks/throttleCallback/useThrottleCallback.tsx
  function useThrottleCallback (line 6) | function useThrottleCallback<F extends (...args: any[]) => ReturnType<F>>(

FILE: apps/tanstack-query-zustand/src/shared/hooks/throttleCallback/useThrottleCallback.types.ts
  type ThrottleControlFunctions (line 1) | interface ThrottleControlFunctions {
  type ThrottleOptions (line 9) | interface ThrottleOptions {
  type ThrottledState (line 15) | type ThrottledState<F extends (...args: any[]) => ReturnType<F>> = ((

FILE: apps/tanstack-query-zustand/src/shared/hooks/useEntityReactions.ts
  type UseEntityReactionsConfig (line 10) | interface UseEntityReactionsConfig {
  type Track (line 22) | type Track = SchemaTrackListItemResource
  type TrackPage (line 23) | type TrackPage = SchemaGetTrackListOutput
  function useEntityReactions (line 25) | function useEntityReactions({ entityId, api, keys }: UseEntityReactionsC...

FILE: apps/tanstack-query-zustand/src/shared/hooks/useHover.ts
  function useHover (line 3) | function useHover<T extends HTMLElement>(): [RefObject<T | null>, boolea...

FILE: apps/tanstack-query-zustand/src/shared/hooks/usePageBackgroundColor.ts
  constant DEFAULT_BACKGROUND_COLOR (line 3) | const DEFAULT_BACKGROUND_COLOR = '#3333a3'

FILE: apps/tanstack-query-zustand/src/shared/model/ui-store.ts
  type UIState (line 3) | interface UIState {

FILE: apps/tanstack-query-zustand/src/shared/types/api-track.types.ts
  type ApiTrack (line 4) | type ApiTrack =

FILE: apps/tanstack-query-zustand/src/shared/types/strict.tsx
  type Strict (line 1) | type Strict<T, U extends T> = U & Record<Exclude<keyof U, keyof T>, never>

FILE: apps/tanstack-query-zustand/src/shared/ui/prerender-ready.tsx
  function PrerenderReady (line 4) | function PrerenderReady() {

FILE: apps/tanstack-query-zustand/src/shared/utils/authStorage.ts
  type TokenData (line 1) | interface TokenData {
  type RefreshTokenData (line 5) | interface RefreshTokenData {
  type AuthStorage (line 9) | interface AuthStorage {
  method saveAccessToken (line 20) | saveAccessToken(accessToken: string) {
  method getAccessToken (line 23) | getAccessToken() {
  method clearAccessToken (line 31) | clearAccessToken() {
  method clearTokens (line 35) | clearTokens() {
  method saveRefreshToken (line 39) | saveRefreshToken(refreshToken: string) {
  method getRefreshToken (line 42) | getRefreshToken() {
  method clearRefreshToken (line 50) | clearRefreshToken() {

FILE: apps/tanstack-query-zustand/src/shared/utils/get-artists-by-track.ts
  function getArtistsByTrack (line 3) | function getArtistsByTrack(

FILE: apps/tanstack-query-zustand/src/shared/utils/get-user-initials.ts
  type FullName (line 1) | type FullName = {

FILE: apps/tanstack-query-zustand/src/shared/utils/join-url.ts
  function joinUrl (line 1) | function joinUrl(...parts: Array<string | number | null | undefined>): s...

FILE: apps/tanstack-query-zustand/src/shared/utils/set-locale.ts
  type Locale (line 3) | type Locale = 'en' | 'ru'
  constant LOCALE_KEY (line 5) | const LOCALE_KEY = 'locale'

FILE: apps/tanstack-query-zustand/src/shared/utils/validators/getType.ts
  function getType (line 2) | function getType(object: any) {

FILE: apps/tanstack-query-zustand/src/shared/utils/validators/inNun.ts
  function isNaN (line 1) | function isNaN(value: number) {

FILE: apps/tanstack-query-zustand/src/shared/utils/validators/isArray.ts
  function isArray (line 4) | function isArray<T>(value: any): value is T[] {

FILE: apps/tanstack-query-zustand/src/shared/utils/validators/isFunction.ts
  function isFunction (line 4) | function isFunction<TFunction extends (...args: any[]) => any>(value: an...

FILE: apps/tanstack-query-zustand/src/shared/utils/validators/isNotEmptyArray.ts
  function isNotEmptyArray (line 1) | function isNotEmptyArray(array?: unknown[]): array is unknown[] {

FILE: apps/tanstack-query-zustand/src/shared/utils/validators/isNull.ts
  function isNull (line 1) | function isNull(value: unknown): value is null {

FILE: apps/tanstack-query-zustand/src/shared/utils/validators/isNumber.ts
  function isNumber (line 3) | function isNumber<T extends number>(value: unknown): value is T {

FILE: apps/tanstack-query-zustand/src/shared/utils/validators/isObject.ts
  function isObject (line 5) | function isObject<T extends Record<string, any>>(value: any): value is T {

FILE: apps/tanstack-query-zustand/src/shared/utils/validators/isString.ts
  function isString (line 4) | function isString<TString extends string>(value: any): value is TString {

FILE: apps/tanstack-query-zustand/src/shared/utils/validators/isUndefined.ts
  function isUndefined (line 3) | function isUndefined(value: unknown): value is undefined {

FILE: apps/tanstack-query-zustand/src/shared/utils/validators/isValid.ts
  function isValid (line 4) | function isValid<T>(value: T | null | undefined): value is T {

FILE: apps/tanstack-query-zustand/src/shared/utils/validators/isValidNumber.ts
  function isValidNumber (line 8) | function isValidNumber(value: any) {

FILE: apps/tanstack-query-zustand/src/shared/utils/validators/isValidObject.ts
  function isValidObject (line 5) | function isValidObject<T extends Record<string, any>>(value: T) {

FILE: apps/tanstack-query-zustand/src/shared/utils/validators/isValidString.ts
  function isValidString (line 7) | function isValidString(value: any) {

FILE: apps/ui-vanilla/src/features/artists/api/artists-api.ts
  constant MOCK_ARTISTS (line 1) | const MOCK_ARTISTS = [

FILE: apps/ui-vanilla/src/features/artists/ui/ArtistCard/ArtistCard.stories.tsx
  type Story (line 12) | type Story = StoryObj<typeof ArtistCard>

FILE: apps/ui-vanilla/src/features/artists/ui/ArtistCard/ArtistCard.tsx
  type Props (line 5) | type Props = {

FILE: apps/ui-vanilla/src/features/auth/ui/ProfileDropdownMenu/ProfileDropdownMenu.stories.tsx
  type Story (line 15) | type Story = StoryObj<typeof ProfileDropdownMenu>

FILE: apps/ui-vanilla/src/features/playlists/api/playlistsApi.ts
  type CurrentUserReaction (line 3) | enum CurrentUserReaction {
  constant MOCK_PLAYLISTS (line 9) | const MOCK_PLAYLISTS = [
  constant MOCK_PLAYLIST (line 342) | const MOCK_PLAYLIST = {

FILE: apps/ui-vanilla/src/features/playlists/ui/PlaylistCard/PlaylistCard.stories.tsx
  type Story (line 13) | type Story = StoryObj<typeof PlaylistCard>

FILE: apps/ui-vanilla/src/features/playlists/ui/PlaylistCard/PlaylistCard.tsx
  type PlaylistCardPropsBase (line 7) | type PlaylistCardPropsBase = {
  type PlaylistCardPropsWithReactions (line 14) | type PlaylistCardPropsWithReactions = PlaylistCardPropsBase & {
  type PlaylistCardPropsWithoutReactions (line 18) | type PlaylistCardPropsWithoutReactions = PlaylistCardPropsBase & {
  type PlaylistCardProps (line 22) | type PlaylistCardProps = PlaylistCardPropsWithReactions | PlaylistCardPr...

FILE: apps/ui-vanilla/src/features/playlists/ui/PlaylistOverview/PlaylistOverview.stories.tsx
  type Story (line 14) | type Story = StoryObj<typeof PlaylistOverview>

FILE: apps/ui-vanilla/src/features/playlists/ui/PlaylistOverview/PlaylistOverview.tsx
  type PlaylistOverviewProps (line 9) | type PlaylistOverviewProps = {

FILE: apps/ui-vanilla/src/features/tags/api/tags-api.ts
  constant MOCK_HASHTAGS (line 1) | const MOCK_HASHTAGS = [
  constant MOCK_5_HASHTAGS (line 13) | const MOCK_5_HASHTAGS = MOCK_HASHTAGS.slice(0, 5)
  type TagDto (line 15) | type TagDto = {

FILE: apps/ui-vanilla/src/features/tags/ui/TagsList/TagsList.stories.tsx
  type Story (line 13) | type Story = StoryObj<typeof TagsList>

FILE: apps/ui-vanilla/src/features/tracks/api/tracksApi.ts
  type CurrentUserReaction (line 1) | enum CurrentUserReaction {
  constant MOCK_TRACKS (line 7) | const MOCK_TRACKS = [

FILE: apps/ui-vanilla/src/features/tracks/api/types.ts
  type CurrentUserReaction (line 1) | enum CurrentUserReaction {

FILE: apps/ui-vanilla/src/features/tracks/ui/TrackCard/TrackCard.stories.tsx
  type Story (line 12) | type Story = StoryObj<typeof TrackCard>

FILE: apps/ui-vanilla/src/features/tracks/ui/TrackCard/TrackCard.tsx
  type Props (line 7) | type Props = {

FILE: apps/ui-vanilla/src/features/tracks/ui/TrackOverview/TrackOverview.stories.tsx
  type Story (line 14) | type Story = StoryObj<typeof TrackOverview>

FILE: apps/ui-vanilla/src/features/tracks/ui/TrackOverview/TrackOverview.tsx
  type TrackOverviewProps (line 9) | type TrackOverviewProps = {

FILE: apps/ui-vanilla/src/features/tracks/ui/TracksTable/TrackTable.stories.tsx
  type Story (line 24) | type Story = StoryObj<typeof TracksTable>
  type ReactionsProps (line 26) | type ReactionsProps =
  type TrackRowData (line 38) | type TrackRowData = {

FILE: apps/ui-vanilla/src/features/tracks/ui/TracksTable/TracksTable.tsx
  type TableColumn (line 13) | type TableColumn = {
  constant TABLE_COLUMNS (line 18) | const TABLE_COLUMNS: TableColumn[] = [
  type TracksTableProps (line 43) | type TracksTableProps<T extends TrackRowData> = {
  type ReactionsProps (line 48) | type ReactionsProps =
  type TrackRowData (line 60) | type TrackRowData = {

FILE: apps/ui-vanilla/src/layout/Header/Header.tsx
  constant IS_AUTH (line 5) | const IS_AUTH = true // temporary data

FILE: apps/ui-vanilla/src/layout/Sidebar/MenuLinks/MenuLinks.tsx
  type MenuLink (line 9) | type MenuLink = {
  type MenuButton (line 15) | type MenuButton = {

FILE: apps/ui-vanilla/src/pages/common/ContentList/ContentList.tsx
  type ContentListProps (line 7) | type ContentListProps<T> = {

FILE: apps/ui-vanilla/src/pages/common/PageWrapper/PageWrapper.tsx
  type PageWrapperProps (line 5) | type PageWrapperProps = {

FILE: apps/ui-vanilla/src/shared/components/AudioPlayer/AudioPlayer.tsx
  type PlayerProps (line 19) | type PlayerProps = {

FILE: apps/ui-vanilla/src/shared/components/Autocomplete/Autocomplete.stories.tsx
  type Story (line 20) | type Story = StoryObj<typeof meta>

FILE: apps/ui-vanilla/src/shared/components/Autocomplete/Autocomplete.tsx
  type AutocompleteOption (line 18) | type AutocompleteOption = {
  type AutocompleteProps (line 24) | type AutocompleteProps = {

FILE: apps/ui-vanilla/src/shared/components/Button/Button.stories.tsx
  type Story (line 15) | type Story = StoryObj<typeof meta>

FILE: apps/ui-vanilla/src/shared/components/Button/Button.tsx
  type ButtonVariant (line 6) | type ButtonVariant = 'primary' | 'secondary'
  type ButtonProps (line 8) | type ButtonProps<T extends ElementType = 'button'> = {

FILE: apps/ui-vanilla/src/shared/components/Card/Card.stories.tsx
  type Story (line 17) | type Story = StoryObj<typeof meta>

FILE: apps/ui-vanilla/src/shared/components/Card/Card.tsx
  type CardProps (line 6) | type CardProps<T extends ElementType = 'div'> = {

FILE: apps/ui-vanilla/src/shared/components/Dialog/Dialog.tsx
  type DialogContextType (line 8) | type DialogContextType = {
  type DialogProps (line 22) | type DialogProps = {
  type DialogHeaderProps (line 70) | type DialogHeaderProps = {
  type DialogContentProps (line 99) | type DialogContentProps = {
  type DialogFooterProps (line 112) | type DialogFooterProps = {

FILE: apps/ui-vanilla/src/shared/components/DropdownMenu/DropdownMenu.stories.tsx
  type Story (line 24) | type Story = StoryObj<typeof meta>

FILE: apps/ui-vanilla/src/shared/components/DropdownMenu/DropdownMenu.tsx
  type DropdownMenuContextType (line 16) | type DropdownMenuContextType = {
  type DropdownMenuProps (line 37) | type DropdownMenuProps = {
  type DropdownMenuTriggerProps (line 102) | type DropdownMenuTriggerProps = {
  type DropdownMenuContentProps (line 141) | type DropdownMenuContentProps = {
  type DropdownMenuItemProps (line 229) | type DropdownMenuItemProps<T extends ElementType = 'button'> = {
  type DropdownMenuSeparatorProps (line 272) | type DropdownMenuSeparatorProps = {

FILE: apps/ui-vanilla/src/shared/components/Hashtag/Tag.stories.tsx
  type Story (line 17) | type Story = StoryObj<typeof meta>

FILE: apps/ui-vanilla/src/shared/components/Hashtag/Tag.tsx
  type HashtagProps (line 6) | type HashtagProps<T extends ElementType = 'button'> = {

FILE: apps/ui-vanilla/src/shared/components/IconButton/IconButton.stories.tsx
  type Story (line 25) | type Story = StoryObj<typeof meta>

FILE: apps/ui-vanilla/src/shared/components/IconButton/IconButton.tsx
  type IconButtonProps (line 6) | type IconButtonProps = {

FILE: apps/ui-vanilla/src/shared/components/ImageUploader/ImageUploader.stories.tsx
  type Story (line 17) | type Story = StoryObj<typeof meta>

FILE: apps/ui-vanilla/src/shared/components/ImageUploader/ImageUploader.tsx
  type ImageUploaderProps (line 10) | type ImageUploaderProps = {

FILE: apps/ui-vanilla/src/shared/components/Pagination/Pagination.stories.tsx
  type Story (line 18) | type Story = StoryObj<typeof meta>

FILE: apps/ui-vanilla/src/shared/components/Pagination/Pagination.tsx
  type PaginationProps (line 9) | type PaginationProps = {
  constant MAX_VISIBLE_PAGES (line 16) | const MAX_VISIBLE_PAGES = 5

FILE: apps/ui-vanilla/src/shared/components/Progress/Progress.stories.tsx
  type Story (line 19) | type Story = StoryObj<typeof meta>

FILE: apps/ui-vanilla/src/shared/components/Progress/Progress.tsx
  type ProgressProps (line 6) | type ProgressProps = {

FILE: apps/ui-vanilla/src/shared/components/ReactionButtons/ReactionButtons.stories.tsx
  type Story (line 18) | type Story = StoryObj<typeof meta>

FILE: apps/ui-vanilla/src/shared/components/ReactionButtons/ReactionButtons.tsx
  type CurrentUserReaction (line 9) | enum CurrentUserReaction {
  type ReactionButtonsProps (line 15) | type ReactionButtonsProps = {
  constant SIZE_MAP (line 24) | const SIZE_MAP = {

FILE: apps/ui-vanilla/src/shared/components/SearchField/SearchField.stories.tsx
  type Story (line 15) | type Story = StoryObj<typeof meta>

FILE: apps/ui-vanilla/src/shared/components/SearchField/SearchField.tsx
  type SearchFieldProps (line 8) | type SearchFieldProps = {

FILE: apps/ui-vanilla/src/shared/components/Select/Select.stories.tsx
  type Story (line 16) | type Story = StoryObj<typeof meta>

FILE: apps/ui-vanilla/src/shared/components/Select/Select.tsx
  type SelectOption (line 10) | type SelectOption = {
  type SelectProps (line 16) | type SelectProps = {

FILE: apps/ui-vanilla/src/shared/components/SortSelect/Select.tsx
  type SelectOption (line 10) | type SelectOption = {
  type SelectProps (line 16) | type SelectProps = {

FILE: apps/ui-vanilla/src/shared/components/Table/Table.stories.tsx
  type Story (line 18) | type Story = StoryObj<typeof meta>

FILE: apps/ui-vanilla/src/shared/components/Table/Table.tsx
  type TableProps (line 10) | type TableProps = {
  type TableHeadProps (line 27) | type TableHeadProps = {
  type TableBodyProps (line 44) | type TableBodyProps = {
  type TableRowProps (line 61) | type TableRowProps = {
  type TableHeaderCellProps (line 78) | type TableHeaderCellProps = {
  type TableCellProps (line 95) | type TableCellProps = {

FILE: apps/ui-vanilla/src/shared/components/Tabs/Tabs.tsx
  type TabsContextType (line 6) | type TabsContextType = {
  type TabsProps (line 25) | type TabsProps = {
  type TabsListProps (line 63) | type TabsListProps = {
  type TabsTriggerProps (line 76) | type TabsTriggerProps = {
  type TabsContentProps (line 108) | type TabsContentProps = {

FILE: apps/ui-vanilla/src/shared/components/TagEditor/TagEditor.tsx
  type TagEditorProps (line 12) | type TagEditorProps = {

FILE: apps/ui-vanilla/src/shared/components/TextField/TextField.stories.tsx
  type Story (line 17) | type Story = StoryObj<typeof meta>

FILE: apps/ui-vanilla/src/shared/components/TextField/TextField.tsx
  type TextFieldSize (line 8) | type TextFieldSize = 'm' | 'l'
  type TextFieldProps (line 10) | type TextFieldProps = {

FILE: apps/ui-vanilla/src/shared/components/Textarea/Textarea.stories.tsx
  type Story (line 15) | type Story = StoryObj<typeof meta>

FILE: apps/ui-vanilla/src/shared/components/Textarea/Textarea.tsx
  type TextareaProps (line 8) | type TextareaProps = {

FILE: apps/ui-vanilla/src/shared/components/Typography/Typography.stories.tsx
  type Story (line 15) | type Story = StoryObj<typeof meta>

FILE: apps/ui-vanilla/src/shared/components/Typography/Typography.tsx
  constant VARIANT_DEFAULT_COMPONENT (line 7) | const VARIANT_DEFAULT_COMPONENT: Record<string, ElementType> = {
  type TypographyVariant (line 18) | type TypographyVariant =
  type Props (line 29) | type Props<T extends ElementType> = {

FILE: apps/ui-vanilla/src/widgets/Player/Player.tsx
  constant MOCK_TRACK (line 7) | const MOCK_TRACK = {

FILE: architecture/microfrontends/player/src/App.tsx
  function App (line 4) | function App() {

FILE: architecture/microfrontends/player/src/main.tsx
  method errorBoundary (line 18) | errorBoundary(err, info, props) {

FILE: architecture/microfrontends/root/src/App.tsx
  function App (line 5) | function App() {

FILE: experiment-apps/musicfun-tanstack-query-orval-small-example/src/app/entrypoint/main.tsx
  type Register (line 16) | interface Register {

FILE: experiment-apps/musicfun-tanstack-query-orval-small-example/src/app/layouts/root-layout.tsx
  function RootLayout (line 12) | function RootLayout() {

FILE: experiment-apps/musicfun-tanstack-query-orval-small-example/src/app/providers/web-socket-provider.tsx
  function WebSocketProvider (line 3) | function WebSocketProvider({ children }: { children: ReactNode }) {

FILE: experiment-apps/musicfun-tanstack-query-orval-small-example/src/app/query-client/query-client.tsx
  type MutationMeta (line 5) | type MutationMeta = {
  type Register (line 14) | interface Register {

FILE: experiment-apps/musicfun-tanstack-query-orval-small-example/src/features/auth/api/auth-api.types.ts
  type LoginRequestPayload (line 4) | type LoginRequestPayload = SchemaLoginRequestPayload

FILE: experiment-apps/musicfun-tanstack-query-orval-small-example/src/features/auth/ui/login-button/use-login.tsx
  function login (line 9) | function login() {

FILE: experiment-apps/musicfun-tanstack-query-orval-small-example/src/features/playlists/add-playlist-form/add-playlist-form.tsx
  type CreatePlaylistRequestPayload (line 10) | type CreatePlaylistRequestPayload = components['schemas']['CreatePlaylis...

FILE: experiment-apps/musicfun-tanstack-query-orval-small-example/src/features/playlists/api/use-playlists-query.tsx
  function usePlaylistsQuery (line 34) | function usePlaylistsQuery(search: string, pageNumber: number, userId: s...

FILE: experiment-apps/musicfun-tanstack-query-orval-small-example/src/features/playlists/edit-playlist-form/edit-playlist-form.tsx
  type Props (line 10) | type Props = {
  type UpdatePlaylistRequestPayload (line 16) | type UpdatePlaylistRequestPayload = components['schemas']['UpdatePlaylis...

FILE: experiment-apps/musicfun-tanstack-query-orval-small-example/src/features/playlists/list/paginated-playlists.tsx
  type Props (line 18) | type Props = {
  type PlaylistCreatedEventPayload (line 24) | type PlaylistCreatedEventPayload = SchemaGetPlaylistOutput
  type PlaylistCreatedEvent (line 27) | type PlaylistCreatedEvent = {

FILE: experiment-apps/musicfun-tanstack-query-orval-small-example/src/features/playlists/list/playlists.tsx
  function QueryStatus (line 49) | function QueryStatus(props: any) {

FILE: experiment-apps/musicfun-tanstack-query-orval-small-example/src/features/playlists/playlist-cover/playlist-cover.tsx
  type PlaylistImagesOutputDTO (line 10) | type PlaylistImagesOutputDTO = components['schemas']['PlaylistImagesOutp...
  type Props (line 12) | type Props = {

FILE: experiment-apps/musicfun-tanstack-query-orval-small-example/src/pages/auth/ui/oauth-callback-page.tsx
  function OauthCallbackPage (line 3) | function OauthCallbackPage() {

FILE: experiment-apps/musicfun-tanstack-query-orval-small-example/src/pages/playlists/ui/my-playlists/my-playlists-page.tsx
  function MyPlaylistsPage (line 11) | function MyPlaylistsPage() {

FILE: experiment-apps/musicfun-tanstack-query-orval-small-example/src/pages/playlists/ui/playlists-with-filters-page.tsx
  function PlaylistsWithFiltersPage (line 3) | function PlaylistsWithFiltersPage() {

FILE: experiment-apps/musicfun-tanstack-query-orval-small-example/src/shared/api/client.ts
  function makeRefreshToken (line 26) | function makeRefreshToken(): Promise<string> {
  method onRequest (line 58) | async onRequest({ request }) {
  method onResponse (line 67) | async onResponse({ request, response }) {

FILE: experiment-apps/musicfun-tanstack-query-orval-small-example/src/shared/api/json-api-error.ts
  type JsonApiError (line 1) | interface JsonApiError {
  type JsonApiErrorDocument (line 10) | interface JsonApiErrorDocument {
  type ExtractError (line 15) | type ExtractError<T> = T extends { error?: infer E } ? E : unknown
  type JsonApiError (line 18) | interface JsonApiError {
  type JsonApiErrorDocument (line 27) | interface JsonApiErrorDocument {
  function isJsonApiErrorDocument (line 32) | function isJsonApiErrorDocument(error: unknown): error is JsonApiErrorDo...
  function parseJsonApiErrors (line 41) | function parseJsonApiErrors(errorDoc: JsonApiErrorDocument): {

FILE: experiment-apps/musicfun-tanstack-query-orval-small-example/src/shared/api/orval/artists/artists.ts
  type SecondParameter (line 35) | type SecondParameter<T extends (...args: never) => unknown> = Parameters...
  type ArtistsControllerCreateArtistMutationResult (line 93) | type ArtistsControllerCreateArtistMutationResult = NonNullable<
  type ArtistsControllerCreateArtistMutationBody (line 96) | type ArtistsControllerCreateArtistMutationBody = CreateArtistRequestPayload
  type ArtistsControllerCreateArtistMutationError (line 97) | type ArtistsControllerCreateArtistMutationError = null | null | null | null
  type ArtistsControllerSearchArtistQueryResult (line 173) | type ArtistsControllerSearchArtistQueryResult = NonNullable<
  type ArtistsControllerSearchArtistQueryError (line 176) | type ArtistsControllerSearchArtistQueryError = unknown
  function useArtistsControllerSearchArtist (line 237) | function useArtistsControllerSearchArtist<
  type ArtistsControllerDeleteArtistMutationResult (line 307) | type ArtistsControllerDeleteArtistMutationResult = NonNullable<
  type ArtistsControllerDeleteArtistMutationError (line 311) | type ArtistsControllerDeleteArtistMutationError = null | null

FILE: experiment-apps/musicfun-tanstack-query-orval-small-example/src/shared/api/orval/authentication/authentication.ts
  type SecondParameter (line 40) | type SecondParameter<T extends (...args: never) => unknown> = Parameters...
  type AuthControllerOauthRedirectQueryResult (line 90) | type AuthControllerOauthRedirectQueryResult = NonNullable<
  type AuthControllerOauthRedirectQueryError (line 93) | type AuthControllerOauthRedirectQueryError = unknown
  function useAuthControllerOauthRedirect (line 154) | function useAuthControllerOauthRedirect<
  type AuthControllerLoginMutationResult (line 234) | type AuthControllerLoginMutationResult = NonNullable<
  type AuthControllerLoginMutationBody (line 237) | type AuthControllerLoginMutationBody = LoginRequestPayload
  type AuthControllerLoginMutationError (line 238) | type AuthControllerLoginMutationError = BadRequestException | Unauthoriz...
  type AuthControllerRefreshMutationResult (line 323) | type AuthControllerRefreshMutationResult = NonNullable<
  type AuthControllerRefreshMutationBody (line 326) | type AuthControllerRefreshMutationBody = RefreshRequestPayload
  type AuthControllerRefreshMutationError (line 327) | type AuthControllerRefreshMutationError = UnauthorizedException
  type AuthControllerLogoutMutationResult (line 409) | type AuthControllerLogoutMutationResult = NonNullable<
  type AuthControllerLogoutMutationBody (line 412) | type AuthControllerLogoutMutationBody = LogoutRequestPayload
  type AuthControllerLogoutMutationError (line 413) | type AuthControllerLogoutMutationError = unknown
  type AuthControllerGetMeQueryResult (line 474) | type AuthControllerGetMeQueryResult = NonNullable<
  type AuthControllerGetMeQueryError (line 477) | type AuthControllerGetMeQueryError = null
  function useAuthControllerGetMe (line 533) | function useAuthControllerGetMe<

FILE: experiment-apps/musicfun-tanstack-query-orval-small-example/src/shared/api/orval/custom-instance.ts
  constant AXIOS_INSTANCE (line 7) | const AXIOS_INSTANCE = Axios.create({

FILE: experiment-apps/musicfun-tanstack-query-orval-small-example/src/shared/api/orval/musicfun.schemas.ts
  type UserOutputDTO (line 12) | interface UserOutputDTO {
  type ImageSizeType (line 22) | type ImageSizeType = (typeof ImageSizeType)[keyof typeof ImageSizeType]
  type ImageDto (line 30) | interface ImageDto {
  type PlaylistImagesOutputDTO (line 43) | interface PlaylistImagesOutputDTO {
  type GetTagOutput (line 48) | interface GetTagOutput {
  type ReactionValue (line 58) | type ReactionValue = (typeof ReactionValue)[keyof typeof ReactionValue]
  type PlaylistAttributesDto (line 66) | interface PlaylistAttributesDto {
  type PlaylistListItemJsonApiData (line 94) | interface PlaylistListItemJsonApiData {
  type GetMyPlaylistsOutput (line 103) | interface GetMyPlaylistsOutput {
  type CreatePlaylistRequestPayload (line 108) | interface CreatePlaylistRequestPayload {
  type PlaylistOutputAttributes (line 123) | interface PlaylistOutputAttributes {
  type PlaylistOutput (line 151) | interface PlaylistOutput {
  type GetPlaylistOutput (line 160) | interface GetPlaylistOutput {
  type UpdatePlaylistRequestPayload (line 165) | interface UpdatePlaylistRequestPayload {
  type ReorderPlaylistsRequestPayload (line 185) | interface ReorderPlaylistsRequestPayload {
  type GetImagesOutput (line 193) | interface GetImagesOutput {
  type GetTracksRequestPayloadSortBy (line 201) | type GetTracksRequestPayloadSortBy =
  type GetTracksRequestPayloadSortDirection (line 212) | type GetTracksRequestPayloadSortDirection =
  type GetTracksRequestPayloadPaginationType (line 223) | type GetTracksRequestPayloadPaginationType =
  type GetTracksRequestPayload (line 231) | interface GetTracksRequestPayload {
  type JsonApiErrorSource (line 266) | interface JsonApiErrorSource {
  type JsonApiErrorCode (line 276) | type JsonApiErrorCode = { [key: string]: unknown }
  type JsonApiErrorMeta (line 281) | type JsonApiErrorMeta = { [key: string]: unknown }
  type JsonApiError (line 283) | interface JsonApiError {
  type JsonApiErrorDocumentMeta (line 301) | type JsonApiErrorDocumentMeta = { [key: string]: unknown }
  type JsonApiErrorDocument (line 303) | interface JsonApiErrorDocument {
  type AttachmentDto (line 310) | interface AttachmentDto {
  type TrackListItemOutputAttributesCurrentUserReaction (line 332) | type TrackListItemOutputAttributesCurrentUserReaction =
  type TrackListItemOutputAttributes (line 341) | interface TrackListItemOutputAttributes {
  type ArtistRelationship (line 354) | interface ArtistRelationship {
  type ArtistsRelationship (line 359) | interface ArtistsRelationship {
  type TrackRelationships (line 363) | interface TrackRelationships {
  type TrackListItemOutput (line 367) | interface TrackListItemOutput {
  type JsonApiMetaWithPagingAndCursor (line 374) | interface JsonApiMetaWithPagingAndCursor {
  type OmitTypeClass (line 394) | interface OmitTypeClass {
  type IncludedArtistOutput (line 399) | interface IncludedArtistOutput {
  type GetTrackListOutput (line 405) | interface GetTrackListOutput {
  type PlaylistTrackAttributesCurrentUserReaction (line 415) | type PlaylistTrackAttributesCurrentUserReaction =
  type PlaylistTrackAttributes (line 425) | interface PlaylistTrackAttributes {
  type GetPlaylistTrackListOutputData (line 445) | interface GetPlaylistTrackListOutputData {
  type JsonApiMeta (line 452) | interface JsonApiMeta {
  type GetPlaylistTrackListOutput (line 456) | interface GetPlaylistTrackListOutput {
  type GetArtistOutput (line 462) | interface GetArtistOutput {
  type TrackDetailsAttributesCurrentUserReaction (line 472) | type TrackDetailsAttributesCurrentUserReaction =
  type TrackDetailsAttributes (line 481) | interface TrackDetailsAttributes {
  type TrackDetailsData (line 531) | interface TrackDetailsData {
  type GetTrackDetailsOutput (line 540) | interface GetTrackDetailsOutput {
  type ReactionOutputValue (line 545) | type ReactionOutputValue = (typeof ReactionOutputValue)[keyof typeof Rea...
  type ReactionOutput (line 553) | interface ReactionOutput {
  type GetPlaylistsRequestPayloadSortBy (line 563) | type GetPlaylistsRequestPayloadSortBy =
  type GetPlaylistsRequestPayloadSortDirection (line 574) | type GetPlaylistsRequestPayloadSortDirection =
  type GetPlaylistsRequestPayload (line 582) | interface GetPlaylistsRequestPayload {
  type JsonApiMetaWithPaging (line 608) | interface JsonApiMetaWithPaging {
  type GetPlaylistsOutput (line 615) | interface GetPlaylistsOutput {
  type ReorderTracksRequestPayload (line 622) | interface ReorderTracksRequestPayload {
  type UpdateTrackRequestPayload (line 630) | interface UpdateTrackRequestPayload {
  type TrackOutputAttributesCurrentUserReaction (line 663) | type TrackOutputAttributesCurrentUserReaction =
  type TrackOutputAttributes (line 672) | interface TrackOutputAttributes {
  type TrackOutput (line 722) | interface TrackOutput {
  type GetTrackOutput (line 731) | interface GetTrackOutput {
  type AddTrackToPlaylistRequestPayload (line 736) | interface AddTrackToPlaylistRequestPayload {
  type CreateArtistRequestPayload (line 741) | interface CreateArtistRequestPayload {
  type LoginRequestPayload (line 750) | interface LoginRequestPayload {
  type RefreshOutput (line 761) | interface RefreshOutput {
  type BadRequestException (line 766) | interface BadRequestException {
  type UnauthorizedException (line 770) | interface UnauthorizedException {
  type RefreshRequestPayload (line 774) | interface RefreshRequestPayload {
  type LogoutRequestPayload (line 778) | interface LogoutRequestPayload {
  type GetMeOutput (line 782) | interface GetMeOutput {
  type CreateTagRequestPayload (line 787) | interface CreateTagRequestPayload {
  type BinaryFile (line 799) | type BinaryFile = Blob
  type PlaylistsPublicControllerGetPlaylistsParams (line 801) | type PlaylistsPublicControllerGetPlaylistsParams = {
  type PlaylistsPublicControllerGetPlaylistsSortBy (line 839) | type PlaylistsPublicControllerGetPlaylistsSortBy =
  type PlaylistsPublicControllerGetPlaylistsSortDirection (line 847) | type PlaylistsPublicControllerGetPlaylistsSortDirection =
  type PlaylistsControllerUploadMainImageBody (line 855) | type PlaylistsControllerUploadMainImageBody = {
  type TracksPublicControllerGetAllTracksParams (line 863) | type TracksPublicControllerGetAllTracksParams = {
  type TracksPublicControllerGetAllTracksSortBy (line 914) | type TracksPublicControllerGetAllTracksSortBy =
  type TracksPublicControllerGetAllTracksSortDirection (line 922) | type TracksPublicControllerGetAllTracksSortDirection =
  type TracksPublicControllerGetAllTracksPaginationType (line 930) | type TracksPublicControllerGetAllTracksPaginationType =
  type TracksControllerUploadTrackCoverBody (line 938) | type TracksControllerUploadTrackCoverBody = {
  type TracksControllerUploadTrackMp3Body (line 942) | type TracksControllerUploadTrackMp3Body = {
  type ArtistsControllerSearchArtistParams (line 947) | type ArtistsControllerSearchArtistParams = {
  type AuthControllerOauthRedirectParams (line 951) | type AuthControllerOauthRedirectParams = {
  type TagsControllerSearchTagsParams (line 959) | type TagsControllerSearchTagsParams = {

FILE: experiment-apps/musicfun-tanstack-query-orval-small-example/src/shared/api/orval/musicfun.ts
  type UserOutputDTO (line 13) | interface UserOutputDTO {
  type ImageSizeType (line 23) | type ImageSizeType = (typeof ImageSizeType)[keyof typeof ImageSizeType]
  type ImageDto (line 31) | interface ImageDto {
  type PlaylistImagesOutputDTO (line 44) | interface PlaylistImagesOutputDTO {
  type GetTagOutput (line 49) | interface GetTagOutput {
  type ReactionValue (line 59) | type ReactionValue = (typeof ReactionValue)[keyof typeof ReactionValue]
  type PlaylistAttributesDto (line 67) | interface PlaylistAttributesDto {
  type PlaylistListItemJsonApiData (line 95) | interface PlaylistListItemJsonApiData {
  type GetMyPlaylistsOutput (line 104) | interface GetMyPlaylistsOutput {
  type CreatePlaylistRequestPayload (line 109) | interface CreatePlaylistRequestPayload {
  type PlaylistOutputAttributes (line 124) | interface PlaylistOutputAttributes {
  type PlaylistOutput (line 152) | interface PlaylistOutput {
  type GetPlaylistOutput (line 161) | interface GetPlaylistOutput {
  type UpdatePlaylistRequestPayload (line 166) | interface UpdatePlaylistRequestPayload {
  type ReorderPlaylistsRequestPayload (line 186) | interface ReorderPlaylistsRequestPayload {
  type GetImagesOutput (line 194) | interface GetImagesOutput {
  type GetTracksRequestPayloadSortBy (line 202) | type GetTracksRequestPayloadSortBy =
  type GetTracksRequestPayloadSortDirection (line 213) | type GetTracksRequestPayloadSortDirection =
  type GetTracksRequestPayloadPaginationType (line 224) | type GetTracksRequestPayloadPaginationType =
  type GetTracksRequestPayload (line 232) | interface GetTracksRequestPayload {
  type JsonApiErrorSource (line 267) | interface JsonApiErrorSource {
  type JsonApiErrorCode (line 277) | type JsonApiErrorCode = { [key: string]: unknown }
  type JsonApiErrorMeta (line 282) | type JsonApiErrorMeta = { [key: string]: unknown }
  type JsonApiError (line 284) | interface JsonApiError {
  type JsonApiErrorDocumentMeta (line 302) | type JsonApiErrorDocumentMeta = { [key: string]: unknown }
  type JsonApiErrorDocument (line 304) | interface JsonApiErrorDocument {
  type AttachmentDto (line 311) | interface AttachmentDto {
  type TrackListItemOutputAttributesCurrentUserReaction (line 333) | type TrackListItemOutputAttributesCurrentUserReaction =
  type TrackListItemOutputAttributes (line 342) | interface TrackListItemOutputAttributes {
  type ArtistRelationship (line 355) | interface ArtistRelationship {
  type ArtistsRelationship (line 360) | interface ArtistsRelationship {
  type TrackRelationships (line 364) | interface TrackRelationships {
  type TrackListItemOutput (line 368) | interface TrackListItemOutput {
  type JsonApiMetaWithPagingAndCursor (line 375) | interface JsonApiMetaWithPagingAndCursor {
  type OmitTypeClass (line 395) | interface OmitTypeClass {
  type IncludedArtistOutput (line 400) | interface IncludedArtistOutput {
  type GetTrackListOutput (line 406) | interface GetTrackListOutput {
  type PlaylistTrackAttributesCurrentUserReaction (line 416) | type PlaylistTrackAttributesCurrentUserReaction =
  type PlaylistTrackAttributes (line 426) | interface PlaylistTrackAttributes {
  type GetPlaylistTrackListOutputData (line 446) | interface GetPlaylistTrackListOutputData {
  type JsonApiMeta (line 453) | interface JsonApiMeta {
  type GetPlaylistTrackListOutput (line 457) | interface GetPlaylistTrackListOutput {
  type GetArtistOutput (line 463) | interface GetArtistOutput {
  type TrackDetailsAttributesCurrentUserReaction (line 473) | type TrackDetailsAttributesCurrentUserReaction =
  type TrackDetailsAttributes (line 482) | interface TrackDetailsAttributes {
  type TrackDetailsData (line 532) | interface TrackDetailsData {
  type GetTrackDetailsOutput (line 541) | interface GetTrackDetailsOutput {
  type ReactionOutputValue (line 546) | type ReactionOutputValue = (typeof ReactionOutputValue)[keyof typeof Rea...
  type ReactionOutput (line 554) | interface ReactionOutput {
  type GetPlaylistsRequestPayloadSortBy (line 564) | type GetPlaylistsRequestPayloadSortBy =
  type GetPlaylistsRequestPayloadSortDirection (line 575) | type GetPlaylistsRequestPayloadSortDirection =
  type GetPlaylistsRequestPayload (line 583) | interface GetPlaylistsRequestPayload {
  type JsonApiMetaWithPaging (line 609) | interface JsonApiMetaWithPaging {
  type GetPlaylistsOutput (line 616) | interface GetPlaylistsOutput {
  type ReorderTracksRequestPayload (line 623) | interface ReorderTracksRequestPayload {
  type UpdateTrackRequestPayload (line 631) | interface UpdateTrackRequestPayload {
  type TrackOutputAttributesCurrentUserReaction (line 664) | type TrackOutputAttributesCurrentUserReaction =
  type TrackOutputAttributes (line 673) | interface TrackOutputAttributes {
  type TrackOutput (line 723) | interface TrackOutput {
  type GetTrackOutput (line 732) | interface GetTrackOutput {
  type AddTrackToPlaylistRequestPayload (line 737) | interface AddTrackToPlaylistRequestPayload {
  type CreateArtistRequestPayload (line 742) | interface CreateArtistRequestPayload {
  type LoginRequestPayload (line 751) | interface LoginRequestPayload {
  type RefreshOutput (line 762) | interface RefreshOutput {
  type BadRequestException (line 767) | interface BadRequestException {
  type UnauthorizedException (line 771) | interface UnauthorizedException {
  type RefreshRequestPayload (line 775) | interface RefreshRequestPayload {
  type LogoutRequestPayload (line 779) | interface LogoutRequestPayload {
  type GetMeOutput (line 783) | interface GetMeOutput {
  type CreateTagRequestPayload (line 788) | interface CreateTagRequestPayload {
  type BinaryFile (line 800) | type BinaryFile = Blob
  type PlaylistsPublicControllerGetPlaylistsParams (line 802) | type PlaylistsPublicControllerGetPlaylistsParams = {
  type PlaylistsPublicControllerGetPlaylistsSortBy (line 840) | type PlaylistsPublicControllerGetPlaylistsSortBy =
  type PlaylistsPublicControllerGetPlaylistsSortDirection (line 848) | type PlaylistsPublicControllerGetPlaylistsSortDirection =
  type PlaylistsControllerUploadMainImageBody (line 856) | type PlaylistsControllerUploadMainImageBody = {
  type TracksPublicControllerGetAllTracksParams (line 864) | type TracksPublicControllerGetAllTracksParams = {
  type TracksPublicControllerGetAllTracksSortBy (line 915) | type TracksPublicControllerGetAllTracksSortBy =
  type TracksPublicControllerGetAllTracksSortDirection (line 923) | type TracksPublicControllerGetAllTracksSortDirection =
  type TracksPublicControllerGetAllTracksPaginationType (line 931) | type TracksPublicControllerGetAllTracksPaginationType =
  type TracksControllerUploadTrackCoverBody (line 939) | type TracksControllerUploadTrackCoverBody = {
  type TracksControllerUploadTrackMp3Body (line 943) | type TracksControllerUploadTrackMp3Body = {
  type ArtistsControllerSearchArtistParams (line 948) | type ArtistsControllerSearchArtistParams = {
  type AuthControllerOauthRedirectParams (line 952) | type AuthControllerOauthRedirectParams = {
  type TagsControllerSearchTagsParams (line 960) | type TagsControllerSearchTagsParams = {
  type SecondParameter (line 967) | type SecondParameter<T extends (...args: never) => unknown> = Parameters...
  type PlaylistsControllerGetMyPlaylistsResult (line 1525) | type PlaylistsControllerGetMyPlaylistsResult = NonNullable<
  type PlaylistsControllerCreatePlaylistResult (line 1528) | type PlaylistsControllerCreatePlaylistResult = NonNullable<
  type PlaylistsPublicControllerGetPlaylistsResult (line 1531) | type PlaylistsPublicControllerGetPlaylistsResult = NonNullable<
  type PlaylistsControllerUpdatePlaylistResult (line 1534) | type PlaylistsControllerUpdatePlaylistResult = NonNullable<
  type PlaylistsControllerDeletePlaylistResult (line 1537) | type PlaylistsControllerDeletePlaylistResult = NonNullable<
  type PlaylistsPublicControllerGetPlaylistByIdResult (line 1540) | type PlaylistsPublicControllerGetPlaylistByIdResult = NonNullable<
  type PlaylistsControllerReorderPlaylistResult (line 1543) | type PlaylistsControllerReorderPlaylistResult = NonNullable<
  type PlaylistsControllerUploadMainImageResult (line 1546) | type PlaylistsControllerUploadMainImageResult = NonNullable<
  type PlaylistsControllerDeleteTrackCoverResult (line 1549) | type PlaylistsControllerDeleteTrackCoverResult = NonNullable<
  type TracksPublicControllerGetAllTracksResult (line 1552) | type TracksPublicControllerGetAllTracksResult = NonNullable<
  type TracksPublicControllerGetPlaylistTracksResult (line 1555) | type TracksPublicControllerGetPlaylistTracksResult = NonNullable<
  type TracksPublicControllerGetTrackDetailsResult (line 1558) | type TracksPublicControllerGetTrackDetailsResult = NonNullable<
  type TracksControllerUpdateTrackResult (line 1561) | type TracksControllerUpdateTrackResult = NonNullable<
  type TracksControllerDeleteTrackCompletelyResult (line 1564) | type TracksControllerDeleteTrackCompletelyResult = NonNullable<
  type TracksPublicControllerLikeTrackResult (line 1567) | type TracksPublicControllerLikeTrackResult = NonNullable<
  type TracksPublicControllerDislikeTrackResult (line 1570) | type TracksPublicControllerDislikeTrackResult = NonNullable<
  type TracksPublicControllerRemoveTrackReactionResult (line 1573) | type TracksPublicControllerRemoveTrackReactionResult = NonNullable<
  type PlaylistsPublicControllerLikePlaylistResult (line 1576) | type PlaylistsPublicControllerLikePlaylistResult = NonNullable<
  type PlaylistsPublicControllerDislikePlaylistResult (line 1579) | type PlaylistsPublicControllerDislikePlaylistResult = NonNullable<
  type PlaylistsPublicControllerRemovePlaylistReactionResult (line 1582) | type PlaylistsPublicControllerRemovePlaylistReactionResult = NonNullable<
  type TracksControllerReorderTrackResult (line 1585) | type TracksControllerReorderTrackResult = NonNullable<
  type TracksControllerAddTrackToPlaylistResult (line 1588) | type TracksControllerAddTrackToPlaylistResult = NonNullable<
  type TracksControllerUnbindTrackFromPlaylistResult (line 1591) | type TracksControllerUnbindTrackFromPlaylistResult = NonNullable<
  type TracksControllerPublishTrackResult (line 1594) | type TracksControllerPublishTrackResult = NonNullable<
  type TracksControllerUploadTrackCoverResult (line 1597) | type TracksControllerUploadTrackCoverResult = NonNullable<
  type TracksControllerDeleteTrackCoverResult (line 1600) | type TracksControllerDeleteTrackCoverResult = NonNullable<
  type TracksControllerUploadTrackMp3Result (line 1603) | type TracksControllerUploadTrackMp3Result = NonNullable<
  type ArtistsControllerCreateArtistResult (line 1606) | type ArtistsControllerCreateArtistResult = NonNullable<
  type ArtistsControllerSearchArtistResult (line 1609) | type ArtistsControllerSearchArtistResult = NonNullable<
  type ArtistsControllerDeleteArtistResult (line 1612) | type ArtistsControllerDeleteArtistResult = NonNullable<
  type AuthControllerOauthRedirectResult (line 1615) | type AuthControllerOauthRedirectResult = NonNullable<
  type AuthControllerLoginResult (line 1618) | type AuthControllerLoginResult = NonNullable<Awaited<ReturnType<typeof a...
  type AuthControllerRefreshResult (line 1619) | type AuthControllerRefreshResult = NonNullable<
  type AuthControllerLogoutResult (line 1622) | type AuthControllerLogoutResult = NonNullable<
  type AuthControllerGetMeResult (line 1625) | type AuthControllerGetMeResult = NonNullable<Awaited<ReturnType<typeof a...
  type TagsControllerCreateTagResult (line 1626) | type TagsControllerCreateTagResult = NonNullable<
  type TagsControllerSearchTagsResult (line 1629) | type TagsControllerSearchTagsResult = NonNullable<
  type TagsControllerDeleteTagResult (line 1632) | type TagsControllerDeleteTagResult = NonNullable<

FILE: experiment-apps/musicfun-tanstack-query-orval-small-example/src/shared/api/orval/playlists-owner/playlists-owner.ts
  type SecondParameter (line 39) | type SecondParameter<T extends (...args: never) => unknown> = Parameters...
  type PlaylistsControllerGetMyPlaylistsQueryResult (line 83) | type PlaylistsControllerGetMyPlaylistsQueryResult = NonNullable<
  type PlaylistsControllerGetMyPlaylistsQueryError (line 86) | type PlaylistsControllerGetMyPlaylistsQueryError = null
  function usePlaylistsControllerGetMyPlaylists (line 145) | function usePlaylistsControllerGetMyPlaylists<
  type PlaylistsControllerCreatePlaylistMutationResult (line 224) | type PlaylistsControllerCreatePlaylistMutationResult = NonNullable<
  type PlaylistsControllerCreatePlaylistMutationBody (line 227) | type PlaylistsControllerCreatePlaylistMutationBody = CreatePlaylistReque...
  type PlaylistsControllerCreatePlaylistMutationError (line 228) | type PlaylistsControllerCreatePlaylistMutationError = null
  type PlaylistsControllerUpdatePlaylistMutationResult (line 309) | type PlaylistsControllerUpdatePlaylistMutationResult = NonNullable<
  type PlaylistsControllerUpdatePlaylistMutationBody (line 312) | type PlaylistsControllerUpdatePlaylistMutationBody = UpdatePlaylistReque...
  type PlaylistsControllerUpdatePlaylistMutationError (line 313) | type PlaylistsControllerUpdatePlaylistMutationError = null | null
  type PlaylistsControllerDeletePlaylistMutationResult (line 385) | type PlaylistsControllerDeletePlaylistMutationResult = NonNullable<
  type PlaylistsControllerDeletePlaylistMutationError (line 389) | type PlaylistsControllerDeletePlaylistMutationError = null | null
  type PlaylistsControllerReorderPlaylistMutationResult (line 470) | type PlaylistsControllerReorderPlaylistMutationResult = NonNullable<
  type PlaylistsControllerReorderPlaylistMutationBody (line 473) | type PlaylistsControllerReorderPlaylistMutationBody = ReorderPlaylistsRe...
  type PlaylistsControllerReorderPlaylistMutationError (line 474) | type PlaylistsControllerReorderPlaylistMutationError = null
  type PlaylistsControllerUploadMainImageMutationResult (line 561) | type PlaylistsControllerUploadMainImageMutationResult = NonNullable<
  type PlaylistsControllerUploadMainImageMutationBody (line 564) | type PlaylistsControllerUploadMainImageMutationBody = PlaylistsControlle...
  type PlaylistsControllerUploadMainImageMutationError (line 565) | type PlaylistsControllerUploadMainImageMutationError = null | null
  type PlaylistsControllerDeleteTrackCoverMutationResult (line 640) | type PlaylistsControllerDeleteTrackCoverMutationResult = NonNullable<
  type PlaylistsControllerDeleteTrackCoverMutationError (line 644) | type PlaylistsControllerDeleteTrackCoverMutationError = null | null

FILE: experiment-apps/musicfun-tanstack-query-orval-small-example/src/shared/api/orval/playlists-public/playlists-public.ts
  type SecondParameter (line 36) | type SecondParameter<T extends (...args: never) => unknown> = Parameters...
  type PlaylistsPublicControllerGetPlaylistsQueryResult (line 91) | type PlaylistsPublicControllerGetPlaylistsQueryResult = NonNullable<
  type PlaylistsPublicControllerGetPlaylistsQueryError (line 94) | type PlaylistsPublicControllerGetPlaylistsQueryError = unknown
  function usePlaylistsPublicControllerGetPlaylists (line 167) | function usePlaylistsPublicControllerGetPlaylists<
  type PlaylistsPublicControllerGetPlaylistByIdQueryResult (line 245) | type PlaylistsPublicControllerGetPlaylistByIdQueryResult = NonNullable<
  type PlaylistsPublicControllerGetPlaylistByIdQueryError (line 248) | type PlaylistsPublicControllerGetPlaylistByIdQueryError = null
  function usePlaylistsPublicControllerGetPlaylistById (line 321) | function usePlaylistsPublicControllerGetPlaylistById<
  type PlaylistsPublicControllerLikePlaylistMutationResult (line 399) | type PlaylistsPublicControllerLikePlaylistMutationResult = NonNullable<
  type PlaylistsPublicControllerLikePlaylistMutationError (line 403) | type PlaylistsPublicControllerLikePlaylistMutationError = null | null | ...
  type PlaylistsPublicControllerDislikePlaylistMutationResult (line 482) | type PlaylistsPublicControllerDislikePlaylistMutationResult = NonNullable<
  type PlaylistsPublicControllerDislikePlaylistMutationError (line 486) | type PlaylistsPublicControllerDislikePlaylistMutationError = null | null...
  type PlaylistsPublicControllerRemovePlaylistReactionMutationResult (line 564) | type PlaylistsPublicControllerRemovePlaylistReactionMutationResult = Non...
  type PlaylistsPublicControllerRemovePlaylistReactionMutationError (line 568) | type PlaylistsPublicControllerRemovePlaylistReactionMutationError = null...

FILE: experiment-apps/musicfun-tanstack-query-orval-small-example/src/shared/api/orval/tags/tags.ts
  type SecondParameter (line 35) | type SecondParameter<T extends (...args: never) => unknown> = Parameters...
  type TagsControllerCreateTagMutationResult (line 93) | type TagsControllerCreateTagMutationResult = NonNullable<
  type TagsControllerCreateTagMutationBody (line 96) | type TagsControllerCreateTagMutationBody = CreateTagRequestPayload
  type TagsControllerCreateTagMutationError (line 97) | type TagsControllerCreateTagMutationError = null | null | null | null
  type TagsControllerSearchTagsQueryResult (line 168) | type TagsControllerSearchTagsQueryResult = NonNullable<
  type TagsControllerSearchTagsQueryError (line 171) | type TagsControllerSearchTagsQueryError = null
  function useTagsControllerSearchTags (line 232) | function useTagsControllerSearchTags<
  type TagsControllerDeleteTagMutationResult (line 302) | type TagsControllerDeleteTagMutationResult = NonNullable<
  type TagsControllerDeleteTagMutationError (line 306) | type TagsControllerDeleteTagMutationError = null | null | null

FILE: experiment-apps/musicfun-tanstack-query-orval-small-example/src/shared/api/orval/tracks-owner/tracks-owner.ts
  type SecondParameter (line 31) | type SecondParameter<T extends (...args: never) => unknown> = Parameters...
  type TracksControllerUpdateTrackMutationResult (line 88) | type TracksControllerUpdateTrackMutationResult = NonNullable<
  type TracksControllerUpdateTrackMutationBody (line 91) | type TracksControllerUpdateTrackMutationBody = UpdateTrackRequestPayload
  type TracksControllerUpdateTrackMutationError (line 92) | type TracksControllerUpdateTrackMutationError = null | null | null
  type TracksControllerDeleteTrackCompletelyMutationResult (line 164) | type TracksControllerDeleteTrackCompletelyMutationResult = NonNullable<
  type TracksControllerDeleteTrackCompletelyMutationError (line 168) | type TracksControllerDeleteTrackCompletelyMutationError = null | null
  type TracksControllerReorderTrackMutationResult (line 250) | type TracksControllerReorderTrackMutationResult = NonNullable<
  type TracksControllerReorderTrackMutationBody (line 253) | type TracksControllerReorderTrackMutationBody = ReorderTracksRequestPayload
  type TracksControllerReorderTrackMutationError (line 254) | type TracksControllerReorderTrackMutationError = null | null | null
  type TracksControllerAddTrackToPlaylistMutationResult (line 337) | type TracksControllerAddTrackToPlaylistMutationResult = NonNullable<
  type TracksControllerAddTrackToPlaylistMutationBody (line 340) | type TracksControllerAddTrackToPlaylistMutationBody = AddTrackToPlaylist...
  type TracksControllerAddTrackToPlaylistMutationError (line 341) | type TracksControllerAddTrackToPlaylistMutationError = null | null
  type TracksControllerUnbindTrackFromPlaylistMutationResult (line 417) | type TracksControllerUnbindTrackFromPlaylistMutationResult = NonNullable<
  type TracksControllerUnbindTrackFromPlaylistMutationError (line 421) | type TracksControllerUnbindTrackFromPlaylistMutationError = null | null
  type TracksControllerPublishTrackMutationResult (line 500) | type TracksControllerPublishTrackMutationResult = NonNullable<
  type TracksControllerPublishTrackMutationError (line 504) | type TracksControllerPublishTrackMutationError = null | null | null
  type TracksControllerUploadTrackCoverMutationResult (line 590) | type TracksControllerUploadTrackCoverMutationResult = NonNullable<
  type TracksControllerUploadTrackCoverMutationBody (line 593) | type TracksControllerUploadTrackCoverMutationBody = TracksControllerUplo...
  type TracksControllerUploadTrackCoverMutationError (line 594) | type TracksControllerUploadTrackCoverMutationError = null | null | null
  type TracksControllerDeleteTrackCoverMutationResult (line 672) | type TracksControllerDeleteTrackCoverMutationResult = NonNullable<
  type TracksControllerDeleteTrackCoverMutationError (line 676) | type TracksControllerDeleteTrackCoverMutationError = null | null
  type TracksControllerUploadTrackMp3MutationResult (line 762) | type TracksControllerUploadTrackMp3MutationResult = NonNullable<
  type TracksControllerUploadTrackMp3MutationBody (line 765) | type TracksControllerUploadTrackMp3MutationBody = TracksControllerUpload...
  type TracksControllerUploadTrackMp3MutationError (line 766) | type TracksControllerUploadTrackMp3MutationError = null | null

FILE: experiment-apps/musicfun-tanstack-query-orval-small-example/src/shared/api/orval/tracks-public/tracks-public.ts
  type SecondParameter (line 38) | type SecondParameter<T extends (...args: never) => unknown> = Parameters...
  type TracksPublicControllerGetAllTracksQueryResult (line 87) | type TracksPublicControllerGetAllTracksQueryResult = NonNullable<
  type TracksPublicControllerGetAllTracksQueryError (line 90) | type TracksPublicControllerGetAllTracksQueryError = JsonApiErrorDocument
  function useTracksPublicControllerGetAllTracks (line 151) | function useTracksPublicControllerGetAllTracks<
  type TracksPublicControllerGetPlaylistTracksQueryResult (line 225) | type TracksPublicControllerGetPlaylistTracksQueryResult = NonNullable<
  type TracksPublicControllerGetPlaylistTracksQueryError (line 228) | type TracksPublicControllerGetPlaylistTracksQueryError = null
  function useTracksPublicControllerGetPlaylistTracks (line 301) | function useTracksPublicControllerGetPlaylistTracks<
  type TracksPublicControllerGetTrackDetailsQueryResult (line 379) | type TracksPublicControllerGetTrackDetailsQueryResult = NonNullable<
  type TracksPublicControllerGetTrackDetailsQueryError (line 382) | type TracksPublicControllerGetTrackDetailsQueryError = null
  function useTracksPublicControllerGetTrackDetails (line 455) | function useTracksPublicControllerGetTrackDetails<
  type TracksPublicControllerLikeTrackMutationResult (line 533) | type TracksPublicControllerLikeTrackMutationResult = NonNullable<
  type TracksPublicControllerLikeTrackMutationError (line 537) | type TracksPublicControllerLikeTrackMutationError = null | null | null
  type TracksPublicControllerDislikeTrackMutationResult (line 613) | type TracksPublicControllerDislikeTrackMutationResult = NonNullable<
  type TracksPublicControllerDislikeTrackMutationError (line 617) | type TracksPublicControllerDislikeTrackMutationError = null | null | null
  type TracksPublicControllerRemoveTrackReactionMutationResult (line 695) | type TracksPublicControllerRemoveTrackReactionMutationResult = NonNullable<
  type TracksPublicControllerRemoveTrackReactionMutationError (line 699) | type TracksPublicControllerRemoveTrackReactionMutationError = null

FILE: experiment-apps/musicfun-tanstack-query-orval-small-example/src/shared/api/request-wrapper.ts
  type ExtractData (line 10) | type ExtractData<T> = T extends { data?: infer D } ? NonNullable<D> : never
  function requestWrapper (line 12) | async function requestWrapper<P extends Promise<{ data?: unknown; error?...

FILE: experiment-apps/musicfun-tanstack-query-orval-small-example/src/shared/api/schema.ts
  type paths (line 6) | interface paths {
  type webhooks (line 552) | type webhooks = Record<string, never>
  type components (line 553) | interface components {
  type SchemaUserOutputDto (line 983) | type SchemaUserOutputDto = components['schemas']['UserOutputDTO']
  type SchemaImageDto (line 984) | type SchemaImageDto = components['schemas']['ImageDto']
  type SchemaPlaylistImagesOutputDto (line 985) | type SchemaPlaylistImagesOutputDto = components['schemas']['PlaylistImag...
  type SchemaReactionValue (line 986) | type SchemaReactionValue = components['schemas']['ReactionValue']
  type SchemaPlaylistAttributesDto (line 987) | type SchemaPlaylistAttributesDto = components['schemas']['PlaylistAttrib...
  type SchemaPlaylistListItemJsonApiData (line 988) | type SchemaPlaylistListItemJsonApiData = components['schemas']['Playlist...
  type SchemaGetMyPlaylistsOutput (line 989) | type SchemaGetMyPlaylistsOutput = components['schemas']['GetMyPlaylistsO...
  type SchemaCreatePlaylistRequestPayload (line 990) | type SchemaCreatePlaylistRequestPayload =
  type SchemaPlaylistOutputAttributes (line 992) | type SchemaPlaylistOutputAttributes = components['schemas']['PlaylistOut...
  type SchemaPlaylistOutput (line 993) | type SchemaPlaylistOutput = components['schemas']['PlaylistOutput']
  type SchemaGetPlaylistOutput (line 994) | type SchemaGetPlaylistOutput = components['schemas']['GetPlaylistOutput']
  type SchemaUpdatePlaylistRequestPayload (line 995) | type SchemaUpdatePlaylistRequestPayload =
  type SchemaReorderPlaylistsRequestPayload (line 997) | type SchemaReorderPlaylistsRequestPayload =
  type SchemaGetImagesOutput (line 999) | type SchemaGetImagesOutput = components['schemas']['GetImagesOutput']
  type SchemaGetTracksRequestPayload (line 1000) | type SchemaGetTracksRequestPayload = components['schemas']['GetTracksReq...
  type SchemaAttachmentDto (line 1001) | type SchemaAttachmentDto = components['schemas']['AttachmentDto']
  type SchemaTrackListItemOutputAttributes (line 1002) | type SchemaTrackListItemOutputAttributes =
  type SchemaArtistRelationship (line 1004) | type SchemaArtistRelationship = components['schemas']['ArtistRelationship']
  type SchemaArtistsRelationship (line 1005) | type SchemaArtistsRelationship = components['schemas']['ArtistsRelations...
  type SchemaTrackRelationships (line 1006) | type SchemaTrackRelationships = components['schemas']['TrackRelationships']
  type SchemaTrackListItemOutput (line 1007) | type SchemaTrackListItemOutput = components['schemas']['TrackListItemOut...
  type SchemaJsonApiMetaWithPagingAndCursor (line 1008) | type SchemaJsonApiMetaWithPagingAndCursor =
  type SchemaOmitTypeClass (line 1010) | type SchemaOmitTypeClass = components['schemas']['OmitTypeClass']
  type SchemaIncludedArtistOutput (line 1011) | type SchemaIncludedArtistOutput = components['schemas']['IncludedArtistO...
  type SchemaGetTrackListOutput (line 1012) | type SchemaGetTrackListOutput = components['schemas']['GetTrackListOutput']
  type SchemaPlaylistTrackAttributes (line 1013) | type SchemaPlaylistTrackAttributes = components['schemas']['PlaylistTrac...
  type SchemaGetPlaylistTrackListOutputData (line 1014) | type SchemaGetPlaylistTrackListOutputData =
  type SchemaJsonApiMeta (line 1016) | type SchemaJsonApiMeta = components['schemas']['JsonApiMeta']
  type SchemaGetPlaylistTrackListOutput (line 1017) | type SchemaGetPlaylistTrackListOutput = components['schemas']['GetPlayli...
  type SchemaGetTagOutput (line 1018) | type SchemaGetTagOutput = components['schemas']['GetTagOutput']
  type SchemaGetArtistOutput (line 1019) | type SchemaGetArtistOutput = components['schemas']['GetArtistOutput']
  type SchemaTrackDetailsAttributes (line 1020) | type SchemaTrackDetailsAttributes = components['schemas']['TrackDetailsA...
  type SchemaTrackDetailsData (line 1021) | type SchemaTrackDetailsData = components['schemas']['TrackDetailsData']
  type SchemaGetTrackDetailsOutput (line 1022) | type SchemaGetTrackDetailsOutput = components['schemas']['GetTrackDetail...
  type SchemaReactionOutput (line 1023) | type SchemaReactionOutput = components['schemas']['ReactionOutput']
  type SchemaGetPlaylistsRequestPayload (line 1024) | type SchemaGetPlaylistsRequestPayload = components['schemas']['GetPlayli...
  type SchemaJsonApiMetaWithPaging (line 1025) | type SchemaJsonApiMetaWithPaging = components['schemas']['JsonApiMetaWit...
  type SchemaGetPlaylistsOutput (line 1026) | type SchemaGetPlaylistsOutput = components['schemas']['GetPlaylistsOutput']
  type SchemaReorderTracksRequestPayload (line 1027) | type SchemaReorderTracksRequestPayload = components['schemas']['ReorderT...
  type SchemaUpdateTrackRequestPayload (line 1028) | type SchemaUpdateTrackRequestPayload = components['schemas']['UpdateTrac...
  type SchemaTrackOutputAttributes (line 1029) | type SchemaTrackOutputAttributes = components['schemas']['TrackOutputAtt...
  type SchemaTrackOutput (line 1030) | type SchemaTrackOutput = components['schemas']['TrackOutput']
  type SchemaGetTrackOutput (line 1031) | type SchemaGetTrackOutput = components['schemas']['GetTrackOutput']
  type SchemaAddTrackToPlaylistRequestPayload (line 1032) | type SchemaAddTrackToPlaylistRequestPayload =
  type SchemaCreateArtistRequestPayload (line 1034) | type SchemaCreateArtistRequestPayload = components['schemas']['CreateArt...
  type SchemaLoginRequestPayload (line 1035) | type SchemaLoginRequestPayload = components['schemas']['LoginRequestPayl...
  type SchemaRefreshOutput (line 1036) | type SchemaRefreshOutput = components['schemas']['RefreshOutput']
  type SchemaBadRequestException (line 1037) | type SchemaBadRequestException = components['schemas']['BadRequestExcept...
  type SchemaUnauthorizedException (line 1038) | type SchemaUnauthorizedException = components['schemas']['UnauthorizedEx...
  type SchemaRefreshRequestPayload (line 1039) | type SchemaRefreshRequestPayload = components['schemas']['RefreshRequest...
  type SchemaLogoutRequestPayload (line 1040) | type SchemaLogoutRequestPayload = components['schemas']['LogoutRequestPa...
  type SchemaGetMeOutput (line 1041) | type SchemaGetMeOutput = components['schemas']['GetMeOutput']
  type SchemaCreateTagRequestPayload (line 1042) | type SchemaCreateTagRequestPayload = components['schemas']['CreateTagReq...
  type SchemaBinaryFile (line 1043) | type SchemaBinaryFile = components['schemas']['BinaryFile']
  type $defs (line 1044) | type $defs = Record<string, never>
  type operations (line 1045) | interface operations {

FILE: experiment-apps/musicfun-tanstack-query-orval-small-example/src/shared/api/socket.ts
  constant BASE (line 5) | const BASE = import.meta.env.VITE_BASE_URL.replace('api/1.0', '')
  constant PATH (line 6) | const PATH = '/api/1.0/ws'
  function createSocket (line 9) | function createSocket(token: string | null): Socket {
  function getSharedSocket (line 18) | function getSharedSocket(token: string | null): Socket {
  function resetSocketWithToken (line 28) | function resetSocketWithToken(token: string | null): Socket {

FILE: experiment-apps/musicfun-tanstack-query-orval-small-example/src/shared/routes/routes.ts
  constant ROUTES (line 1) | const ROUTES = {

FILE: experiment-apps/musicfun-tanstack-query-orval-small-example/src/shared/ui/header/header.component.tsx
  type Props (line 6) | type Props = {

FILE: experiment-apps/musicfun-tanstack-query-orval-small-example/src/shared/ui/pagination/pagination-nav/pagination-nav.tsx
  type Props (line 4) | type Props = {
  constant SIBLING_COUNT (line 10) | const SIBLING_COUNT = 1

FILE: experiment-apps/musicfun-tanstack-query-orval-small-example/src/shared/ui/pagination/pagination.tsx
  type Props (line 4) | type Props = {

FILE: experiment-apps/musicfun-tanstack-query-small-example/src/app/entrypoint/main.tsx
  type Register (line 16) | interface Register {

FILE: experiment-apps/musicfun-tanstack-query-small-example/src/app/layouts/root-layout.tsx
  function RootLayout (line 12) | function RootLayout() {

FILE: experiment-apps/musicfun-tanstack-query-small-example/src/app/providers/web-socket-provider.tsx
  function WebSocketProvider (line 3) | function WebSocketProvider({ children }: { children: ReactNode }) {

FILE: experiment-apps/musicfun-tanstack-query-small-example/src/app/query-client/query-client.tsx
  type MutationMeta (line 5) | type MutationMeta = {
  type Register (line 14) | interface Register {

FILE: experiment-apps/musicfun-tanstack-query-small-example/src/features/auth/api/auth-api.types.ts
  type LoginRequestPayload (line 4) | type LoginRequestPayload = SchemaLoginRequestPayload

FILE: experiment-apps/musicfun-tanstack-query-small-example/src/features/auth/ui/login-button/use-login.tsx
  function login (line 9) | function login() {

FILE: experiment-apps/musicfun-tanstack-query-small-example/src/features/playlists/add-playlist-form/add-playlist-form.tsx
  type CreatePlaylistRequestPayload (line 10) | type CreatePlaylistRequestPayload = components['schemas']['CreatePlaylis...

FILE: experiment-apps/musicfun-tanstack-query-small-example/src/features/playlists/api/use-playlists-query.tsx
  function usePlaylistsQuery (line 34) | function usePlaylistsQuery(search: string, pageNumber: number, userId: s...

FILE: experiment-apps/musicfun-tanstack-query-small-example/src/features/playlists/edit-playlist-form/edit-playlist-form.tsx
  type Props (line 10) | type Props = {
  type UpdatePlaylistRequestPayload (line 16) | type UpdatePlaylistRequestPayload = components['schemas']['UpdatePlaylis...

FILE: experiment-apps/musicfun-tanstack-query-small-example/src/features/playlists/list/paginated-playlists.tsx
  type Props (line 17) | type Props = {
  type PlaylistCreatedEventPayload (line 23) | type PlaylistCreatedEventPayload = SchemaGetPlaylistOutput
  type PlaylistCreatedEvent (line 26) | type PlaylistCreatedEvent = {

FILE: experiment-apps/musicfun-tanstack-query-small-example/src/features/playlists/list/playlists.tsx
  function QueryStatus (line 49) | function QueryStatus(props: any) {

FILE: experiment-apps/musicfun-tanstack-query-small-example/src/features/playlists/playlist-cover/playlist-cover.tsx
  type PlaylistImagesOutputDTO (line 10) | type PlaylistImagesOutputDTO = components['schemas']['PlaylistImagesOutp...
  type Props (line 12) | type Props = {

FILE: experiment-apps/musicfun-tanstack-query-small-example/src/pages/auth/ui/oauth-callback-page.tsx
  function OauthCallbackPage (line 3) | function OauthCallbackPage() {

FILE: experiment-apps/musicfun-tanstack-query-small-example/src/pages/playlists/ui/my-playlists/my-playlists-page.tsx
  function MyPlaylistsPage (line 11) | function MyPlaylistsPage() {

FILE: experiment-apps/musicfun-tanstack-query-small-example/src/pages/playlists/ui/playlists-with-filters-page.tsx
  function PlaylistsWithFiltersPage (line 3) | function PlaylistsWithFiltersPage() {

FILE: experiment-apps/musicfun-tanstack-query-small-example/src/shared/api/client.ts
  function makeRefreshToken (line 26) | function makeRefreshToken(): Promise<string> {
  method onRequest (line 58) | async onRequest({ request }) {
  method onResponse (line 67) | async onResponse({ request, response }) {

FILE: experiment-apps/musicfun-tanstack-query-small-example/src/shared/api/json-api-error.ts
  type JsonApiError (line 1) | interface JsonApiError {
  type JsonApiErrorDocument (line 10) | interface JsonApiErrorDocument {
  type ExtractError (line 15) | type ExtractError<T> = T extends { error?: infer E } ? E : unknown
  type JsonApiError (line 18) | interface JsonApiError {
  type JsonApiErrorDocument (line 27) | interface JsonApiErrorDocument {
  function isJsonApiErrorDocument (line 32) | function isJsonApiErrorDocument(error: unknown): error is JsonApiErrorDo...
  function parseJsonApiErrors (line 41) | function parseJsonApiErrors(errorDoc: JsonApiErrorDocument): {

FILE: experiment-apps/musicfun-tanstack-query-small-example/src/shared/api/request-wrapper.ts
  type ExtractData (line 10) | type ExtractData<T> = T extends { data?: infer D } ? NonNullable<D> : never
  function requestWrapper (line 12) | async function requestWrapper<P extends Promise<{ data?: unknown; error?...

FILE: experiment-apps/musicfun-tanstack-query-small-example/src/shared/api/schema.ts
  type paths (line 6) | interface paths {
  type webhooks (line 552) | type webhooks = Record<string, never>
  type components (line 553) | interface components {
  type SchemaUserOutputDto (line 983) | type SchemaUserOutputDto = components['schemas']['UserOutputDTO']
  type SchemaImageDto (line 984) | type SchemaImageDto = components['schemas']['ImageDto']
  type SchemaPlaylistImagesOutputDto (line 985) | type SchemaPlaylistImagesOutputDto = components['schemas']['PlaylistImag...
  type SchemaReactionValue (line 986) | type SchemaReactionValue = components['schemas']['ReactionValue']
  type SchemaPlaylistAttributesDto (line 987) | type SchemaPlaylistAttributesDto = components['schemas']['PlaylistAttrib...
  type SchemaPlaylistListItemJsonApiData (line 988) | type SchemaPlaylistListItemJsonApiData = components['schemas']['Playlist...
  type SchemaGetMyPlaylistsOutput (line 989) | type SchemaGetMyPlaylistsOutput = components['schemas']['GetMyPlaylistsO...
  type SchemaCreatePlaylistRequestPayload (line 990) | type SchemaCreatePlaylistRequestPayload =
  type SchemaPlaylistOutputAttributes (line 992) | type SchemaPlaylistOutputAttributes = components['schemas']['PlaylistOut...
  type SchemaPlaylistOutput (line 993) | type SchemaPlaylistOutput = components['schemas']['PlaylistOutput']
  type SchemaGetPlaylistOutput (line 994) | type SchemaGetPlaylistOutput = components['schemas']['GetPlaylistOutput']
  type SchemaUpdatePlaylistRequestPayload (line 995) | type SchemaUpdatePlaylistRequestPayload =
  type SchemaReorderPlaylistsRequestPayload (line 997) | type SchemaReorderPlaylistsRequestPayload =
  type SchemaGetImagesOutput (line 999) | type SchemaGetImagesOutput = components['schemas']['GetImagesOutput']
  type SchemaGetTracksRequestPayload (line 1000) | type SchemaGetTracksRequestPayload = components['schemas']['GetTracksReq...
  type SchemaAttachmentDto (line 1001) | type SchemaAttachmentDto = components['schemas']['AttachmentDto']
  type SchemaTrackListItemOutputAttributes (line 1002) | type SchemaTrackListItemOutputAttributes =
  type SchemaArtistRelationship (line 1004) | type SchemaArtistRelationship = components['schemas']['ArtistRelationship']
  type SchemaArtistsRelationship (line 1005) | type SchemaArtistsRelationship = components['schemas']['ArtistsRelations...
  type SchemaTrackRelationships (line 1006) | type SchemaTrackRelationships = components['schemas']['TrackRelationships']
  type SchemaTrackListItemOutput (line 1007) | type SchemaTrackListItemOutput = components['schemas']['TrackListItemOut...
  type SchemaJsonApiMetaWithPagingAndCursor (line 1008) | type SchemaJsonApiMetaWithPagingAndCursor =
  type SchemaOmitTypeClass (line 1010) | type SchemaOmitTypeClass = components['schemas']['OmitTypeClass']
  type SchemaIncludedArtistOutput (line 1011) | type SchemaIncludedArtistOutput = components['schemas']['IncludedArtistO...
  type SchemaGetTrackListOutput (line 1012) | type SchemaGetTrackListOutput = components['schemas']['GetTrackListOutput']
  type SchemaPlaylistTrackAttributes (line 1013) | type SchemaPlaylistTrackAttributes = components['schemas']['PlaylistTrac...
  type SchemaGetPlaylistTrackListOutputData (line 1014) | type SchemaGetPlaylistTrackListOutputData =
  type SchemaJsonApiMeta (line 1016) | type SchemaJsonApiMeta = components['schemas']['JsonApiMeta']
  type SchemaGetPlaylistTrackListOutput (line 1017) | type SchemaGetPlaylistTrackListOutput = components['schemas']['GetPlayli...
  type SchemaGetTagOutput (line 1018) | type SchemaGetTagOutput = components['schemas']['GetTagOutput']
  type SchemaGetArtistOutput (line 1019) | type SchemaGetArtistOutput = components['schemas']['GetArtistOutput']
  type SchemaTrackDetailsAttributes (line 1020) | type SchemaTrackDetailsAttributes = components['schemas']['TrackDetailsA...
  type SchemaTrackDetailsData (line 1021) | type SchemaTrackDetailsData = components['schemas']['TrackDetailsData']
  type SchemaGetTrackDetailsOutput (line 1022) | type SchemaGetTrackDetailsOutput = components['schemas']['GetTrackDetail...
  type SchemaReactionOutput (line 1023) | type SchemaReactionOutput = components['schemas']['ReactionOutput']
  type SchemaGetPlaylistsRequestPayload (line 1024) | type SchemaGetPlaylistsRequestPayload = components['schemas']['GetPlayli...
  type SchemaJsonApiMetaWithPaging (line 1025) | type SchemaJsonApiMetaWithPaging = components['schemas']['JsonApiMetaWit...
  type SchemaGetPlaylistsOutput (line 1026) | type SchemaGetPlaylistsOutput = components['schemas']['GetPlaylistsOutput']
  type SchemaReorderTracksRequestPayload (line 1027) | type SchemaReorderTracksRequestPayload = components['schemas']['ReorderT...
  type SchemaUpdateTrackRequestPayload (line 1028) | type SchemaUpdateTrackRequestPayload = components['schemas']['UpdateTrac...
  type SchemaTrackOutputAttributes (line 1029) | type SchemaTrackOutputAttributes = components['schemas']['TrackOutputAtt...
  type SchemaTrackOutput (line 1030) | type SchemaTrackOutput = components['schemas']['TrackOutput']
  type SchemaGetTrackOutput (line 1031) | type SchemaGetTrackOutput = components['schemas']['GetTrackOutput']
  type SchemaAddTrackToPlaylistRequestPayload (line 1032) | type SchemaAddTrackToPlaylistRequestPayload =
  type SchemaCreateArtistRequestPayload (line 1034) | type SchemaCreateArtistRequestPayload = components['schemas']['CreateArt...
  type SchemaLoginRequestPayload (line 1035) | type SchemaLoginRequestPayload = components['schemas']['LoginRequestPayl...
  type SchemaRefreshOutput (line 1036) | type SchemaRefreshOutput = components['schemas']['RefreshOutput']
  type SchemaBadRequestException (line 1037) | type SchemaBadRequestException = components['schemas']['BadRequestExcept...
  type SchemaUnauthorizedException (line 1038) | type SchemaUnauthorizedException = components['schemas']['UnauthorizedEx...
  type SchemaRefreshRequestPayload (line 1039) | type SchemaRefreshRequestPayload = components['schemas']['RefreshRequest...
  type SchemaLogoutRequestPayload (line 1040) | type SchemaLogoutRequestPayload = components['schemas']['LogoutRequestPa...
  type SchemaGetMeOutput (line 1041) | type SchemaGetMeOutput = components['schemas']['GetMeOutput']
  type SchemaCreateTagRequestPayload (line 1042) | type SchemaCreateTagRequestPayload = components['schemas']['CreateTagReq...
  type SchemaBinaryFile (line 1043) | type SchemaBinaryFile = components['schemas']['BinaryFile']
  type $defs (line 1044) | type $defs = Record<string, never>
  type operations (line 1045) | interface operations {

FILE: experiment-apps/musicfun-tanstack-query-small-example/src/shared/api/socket.ts
  constant BASE (line 5) | const BASE = import.meta.env.VITE_BASE_URL.replace('api/1.0', '')
  constant PATH (line 6) | const PATH = '/api/1.0/ws'
  function createSocket (line 9) | function createSocket(token: string | null): Socket {
  function getSharedSocket (line 18) | function getSharedSocket(token: string | null): Socket {
  function resetSocketWithToken (line 28) | function resetSocketWithToken(token: string | null): Socket {

FILE: experiment-apps/musicfun-tanstack-query-small-example/src/shared/routes/routes.ts
  constant ROUTES (line 1) | const ROUTES = {

FILE: experiment-apps/musicfun-tanstack-query-small-example/src/shared/ui/header/header.component.tsx
  type Props (line 6) | type Props = {

FILE: experiment-apps/musicfun-tanstack-query-small-example/src/shared/ui/pagination/pagination-nav/pagination-nav.tsx
  type Props (line 4) | type Props = {
  constant SIBLING_COUNT (line 10) | const SIBLING_COUNT = 1

FILE: experiment-apps/musicfun-tanstack-query-small-example/src/shared/ui/pagination/pagination.tsx
  type Props (line 4) | type Props = {

FILE: experiment-apps/trelly-rtk/src/app/model/app-slice.ts
  type ThemeMode (line 54) | type ThemeMode = "dark" | "light"

FILE: experiment-apps/trelly-rtk/src/app/model/store.ts
  type RootState (line 18) | type RootState = ReturnType<typeof store.getState>
  type AppDispatch (line 19) | type AppDispatch = typeof store.dispatch

FILE: experiment-apps/trelly-rtk/src/common/components/CreateItemForm/CreateItemForm.tsx
  type Props (line 6) | type Props = {

FILE: experiment-apps/trelly-rtk/src/common/components/EditableSpan/EditableSpan.tsx
  type Props (line 4) | type Props = {

FILE: experiment-apps/trelly-rtk/src/common/components/NavButton/NavButton.ts
  type Props (line 4) | type Props = {

FILE: experiment-apps/trelly-rtk/src/common/components/ProtectedRoute/ProtectedRoute.tsx
  type Props (line 6) | type Props = {

FILE: experiment-apps/trelly-rtk/src/common/constants/constants.ts
  constant PAGE_SIZE (line 1) | const PAGE_SIZE = 4
  constant LOCALSTORAGE_KEYS (line 3) | const LOCALSTORAGE_KEYS = {

FILE: experiment-apps/trelly-rtk/src/common/enums/enums.ts
  type TaskStatus (line 1) | enum TaskStatus {
  type TaskPriority (line 8) | enum TaskPriority {
  type ResultCode (line 16) | enum ResultCode {

FILE: experiment-apps/trelly-rtk/src/common/types/types.ts
  type FieldError (line 1) | type FieldError = {
  type BaseResponse (line 6) | type BaseResponse<T = {}> = {
  type RequestStatus (line 13) | type RequestStatus = "idle" | "loading" | "succeeded" | "failed"
  type Meta (line 15) | type Meta = {

FILE: experiment-apps/trelly-rtk/src/common/utils/isErrorWithMessage.ts
  function isErrorWithMessage (line 1) | function isErrorWithMessage(error: unknown): error is { message: string } {

FILE: experiment-apps/trelly-rtk/src/features/auth/api/authApi.ts
  method onQueryStarted (line 13) | async onQueryStarted(_args, { queryFulfilled }) {
  method onQueryStarted (line 27) | async onQueryStarted(_args, { queryFulfilled, dispatch }) {

FILE: experiment-apps/trelly-rtk/src/features/auth/api/authApi.types.ts
  type OAuthResponse (line 2) | type OAuthResponse = {
  type LoginArgs (line 8) | type LoginArgs = {

FILE: experiment-apps/trelly-rtk/src/features/auth/lib/schemas/loginSchema.ts
  type Inputs (line 12) | type Inputs = z.infer<typeof loginSchema>

FILE: experiment-apps/trelly-rtk/src/features/boards/api/boardsApi.types.ts
  type FilterValues (line 5) | type FilterValues = "all" | "active" | "completed"
  type BoardsResponse (line 7) | type BoardsResponse = {
  type Board (line 12) | type Board = {
  type DomainBoard (line 18) | type DomainBoard = { filter: FilterValues } & Board
  type DomainBoardResponse (line 20) | type DomainBoardResponse = {
  type BoardAttributes (line 25) | type BoardAttributes = {
  type Images (line 36) | type Images = {
  type Cover (line 40) | type Cover = {
  type UpdateBoardArgs (line 49) | type UpdateBoardArgs = {
  type Todolist (line 64) | type Todolist = z.infer<typeof TodolistSchema>

FILE: experiment-apps/trelly-rtk/src/features/boards/ui/Boards/BoardItem/BoardItem.tsx
  type Props (line 9) | type Props = {

FILE: experiment-apps/trelly-rtk/src/features/boards/ui/Boards/BoardItem/BoardTitle/BoardTitle.tsx
  type Props (line 10) | type Props = {

FILE: experiment-apps/trelly-rtk/src/features/boards/ui/Boards/BoardItem/FilterButtons/FilterButtons.tsx
  type Props (line 10) | type Props = {

FILE: experiment-apps/trelly-rtk/src/features/tasks/api/tasksApi.types.ts
  type GetBoardTasksResponse (line 6) | type GetBoardTasksResponse = {
  type AddTaskResponse (line 11) | type AddTaskResponse = {
  type UpdateTaskResponse (line 23) | type UpdateTaskResponse = {
  type Task (line 51) | type Task = {
  type TaskAttributes (line 57) | type TaskAttributes = {
  type DomainTask (line 83) | type DomainTask = z.infer<typeof DomainTaskSchema>
  type UpdateTaskModel (line 85) | type UpdateTaskModel = {

FILE: experiment-apps/trelly-rtk/src/features/tasks/ui/Tasks/TaskItem/TaskItem.tsx
  type Props (line 16) | type Props = {

FILE: experiment-apps/trelly-rtk/src/features/tasks/ui/Tasks/Tasks.tsx
  type Props (line 12) | type Props = {

FILE: experiment-apps/trelly-rtk/src/features/tasks/ui/Tasks/TasksPagination/TasksPagination.tsx
  type Props (line 9) | type Props = {

FILE: packages/musicfun-api-sdk/src/api/artists/artistsApi.types.ts
  type Artist (line 1) | type Artist = {

FILE: packages/musicfun-api-sdk/src/api/auth/authApi.ts
  type OAuthLoginRequest (line 28) | type OAuthLoginRequest = {

FILE: packages/musicfun-api-sdk/src/api/auth/authApi.types.ts
  type MeResponseResponse (line 1) | type MeResponseResponse = {
  type AuthTokensResponse (line 6) | type AuthTokensResponse = {
  type RefreshTokensRequest (line 11) | type RefreshTokensRequest = {

FILE: packages/musicfun-api-sdk/src/api/playlists/playlistsApi.types.ts
  type Playlist (line 4) | type Playlist = {
  type PlaylistAttributes (line 10) | type PlaylistAttributes = {
  type PlaylistsResponse (line 22) | type PlaylistsResponse = {
  type CreatePlaylistArgs (line 28) | type CreatePlaylistArgs = Pick<PlaylistAttributes, 'title' | 'description'>
  type UpdatePlaylistArgs (line 30) | type UpdatePlaylistArgs = Partial<Pick<PlaylistAttributes, 'title' | 'de...

FILE: packages/musicfun-api-sdk/src/api/tags/tagsApi.types.ts
  type Tag (line 1) | type Tag = {

FILE: packages/musicfun-api-sdk/src/api/tracks/tracksApi.types.ts
  type TrackDetails (line 7) | type TrackDetails<T> = {
  type BaseAttributes (line 14) | type BaseAttributes = {
  type FetchTracksAttributes (line 21) | type FetchTracksAttributes = BaseAttributes & {
  type TrackDetailAttributes (line 25) | type TrackDetailAttributes = BaseAttributes & {
  type PlaylistItemAttributes (line 40) | type PlaylistItemAttributes = BaseAttributes & {
  type TrackAttachment (line 46) | type TrackAttachment = {
  type FetchTracksResponse (line 59) | type FetchTracksResponse = {
  type FetchPlaylistsTracksResponse (line 64) | type FetchPlaylistsTracksResponse = {
  type ReactionResponse (line 69) | type ReactionResponse = {
  type FetchTracksArgs (line 77) | type FetchTracksArgs = {
  type UpdateTrackArgs (line 83) | type UpdateTrackArgs = {
  type TrackVisibility (line 93) | type TrackVisibility = 'private' | 'public'
  type TrackProcessingStatus (line 95) | type TrackProcessingStatus = 'uploaded' | 'converting' | 'ready'

FILE: packages/musicfun-api-sdk/src/common/types/common.types.ts
  type Nullable (line 1) | type Nullable<T> = T | null
  type Meta (line 3) | type Meta = {

FILE: packages/musicfun-api-sdk/src/common/types/enums.ts
  type CurrentUserReaction (line 7) | type CurrentUserReaction = (typeof CurrentUserReaction)[keyof typeof Cur...

FILE: packages/musicfun-api-sdk/src/common/types/playlists-tracks.types.ts
  type Images (line 1) | type Images = {
  type Cover (line 5) | type Cover = {
  type User (line 13) | type User = {

FILE: packages/musicfun-api-sdk/src/v2/request.ts
  type ApiClientConfig (line 5) | interface ApiClientConfig {
  type RequestOptions (line 13) | interface RequestOptions {
  type RequestInterceptor (line 20) | type RequestInterceptor = (
  type ResponseInterceptor (line 25) | type ResponseInterceptor = (response: Response, retry: () => Promise<Res...
  type ApiResponse (line 27) | interface ApiResponse<T> {
  class ApiClient (line 32) | class ApiClient {
    method constructor (line 39) | constructor(config: ApiClientConfig) {
    method getConfig (line 46) | getConfig(): ApiClientConfig {
    method addRequestInterceptor (line 50) | addRequestInterceptor(fn: RequestInterceptor) {
    method addResponseInterceptor (line 54) | addResponseInterceptor(fn: ResponseInterceptor) {
    method authRequestInterceptor (line 58) | private async authRequestInterceptor(
    method tokenRefreshInterceptor (line 69) | private async tokenRefreshInterceptor(
    method handleRefresh (line 80) | private async handleRefresh(): Promise<void> {
    method buildUrl (line 105) | private buildUrl(path: string, params?: Record<string, any>): string {
    method sendRequest (line 115) | private async sendRequest(
    method request (line 164) | private async request<T>(
    method get (line 186) | get<T>(path: string, opts?: RequestOptions): Promise<ApiResponse<T>> {
    method post (line 191) | post<T, B = any>(path: string, body: B, opts?: RequestOptions): Promis...
    method put (line 196) | put<T, B = any>(path: string, body: B, opts?: RequestOptions): Promise...
    method delete (line 201) | delete<T>(path: string, opts?: RequestOptions): Promise<ApiResponse<T>> {
  function createApiClient (line 209) | function createApiClient(config: ApiClientConfig): ApiClient {
  function getApiClient (line 214) | function getApiClient(): ApiClient {

FILE: youtube/rtk-query/lesson1/src/app/model/store.ts
  type RootState (line 13) | type RootState = ReturnType<typeof store.getState>

FILE: youtube/rtk-query/lesson1/src/common/components/LinearProgress/LinearProgress.tsx
  type Props (line 3) | type Props = {

FILE: youtube/rtk-query/lesson1/src/common/components/Pagination/Pagination.tsx
  type Props (line 5) | type Props = {

FILE: youtube/rtk-query/lesson1/src/common/constants/constants.ts
  constant AUTH_KEYS (line 1) | const AUTH_KEYS = {
  constant SOCKET_EVENTS (line 6) | const SOCKET_EVENTS = {
  type SocketEvents (line 16) | type SocketEvents = (typeof SOCKET_EVENTS)[keyof typeof SOCKET_EVENTS]

FILE: youtube/rtk-query/lesson1/src/common/hooks/useInfiniteScroll.ts
  type Props (line 3) | type Props = {

FILE: youtube/rtk-query/lesson1/src/common/types/types.ts
  type Tag (line 5) | type Tag = z.infer<typeof tagSchema>
  type User (line 6) | type User = z.infer<typeof userSchema>
  type Cover (line 7) | type Cover = z.infer<typeof coverSchema>
  type Images (line 8) | type Images = z.infer<typeof imagesSchema>
  type CurrentUserReaction (line 9) | type CurrentUserReaction = z.infer<typeof currentUserReactionSchema>

FILE: youtube/rtk-query/lesson1/src/common/utils/getPaginationPages.ts
  constant SIBLING_COUNT (line 1) | const SIBLING_COUNT = 1

FILE: youtube/rtk-query/lesson1/src/common/utils/isErrorWithDetailArray.ts
  function isErrorWithDetailArray (line 1) | function isErrorWithDetailArray(error: unknown): error is { errors: { de
Condensed preview — 2217 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (3,525K chars).
[
  {
    "path": ".github/workflows/ci-rtk.yml",
    "chars": 628,
    "preview": "name: CI - RTK Query Build\n\non:\n  push:\n    branches:\n      - develop\n    paths:\n      - 'apps/rtk-query/**'\n  pull_requ"
  },
  {
    "path": ".github/workflows/ci-tanstack.yml",
    "chars": 685,
    "preview": "name: CI - TanStack Query Build\n\non:\n  push:\n    branches:\n      - develop\n    paths:\n      - 'apps/tanstack-query-zusta"
  },
  {
    "path": ".github/workflows/deploy-effector.yml",
    "chars": 998,
    "preview": "name: Deploy Effector App\n\non:\n  workflow_dispatch:\n\nconcurrency:\n  group: gh-pages-deploy\n  cancel-in-progress: false\n\n"
  },
  {
    "path": ".github/workflows/deploy-reatom.yml",
    "chars": 946,
    "preview": "name: Deploy Reatom App\n\non:\n  workflow_dispatch:\n\nconcurrency:\n  group: gh-pages-deploy\n  cancel-in-progress: false\n\npe"
  },
  {
    "path": ".github/workflows/deploy-root.yml",
    "chars": 822,
    "preview": "name: Deploy Root Landing Page\n\non:\n  workflow_dispatch:\n\nconcurrency:\n  group: gh-pages-deploy\n  cancel-in-progress: fa"
  },
  {
    "path": ".github/workflows/deploy-rtk.yml",
    "chars": 963,
    "preview": "name: Deploy RTK Query App\n\non:\n  workflow_dispatch:\n\nconcurrency:\n  group: gh-pages-deploy\n  cancel-in-progress: false\n"
  },
  {
    "path": ".github/workflows/deploy-tanstack.yml",
    "chars": 1025,
    "preview": "name: Deploy TanStack Query App\n\non:\n  workflow_dispatch:\n\nconcurrency:\n  group: gh-pages-deploy\n  cancel-in-progress: f"
  },
  {
    "path": ".github/workflows/deploy.yml",
    "chars": 3131,
    "preview": "name: Deploy MusicFun Apps to GitHub Pages\n\non:\n  workflow_dispatch:\n\npermissions:\n  contents: read\n  pages: write\n  id-"
  },
  {
    "path": ".gitignore",
    "chars": 360,
    "preview": "# Logs\nlogs\n*.log\nnpm-debug.log*\nyarn-debug.log*\nyarn-error.log*\npnpm-debug.log*\nlerna-debug.log*\n\nnode_modules\ndist\ndis"
  },
  {
    "path": ".husky/pre-commit",
    "chars": 668,
    "preview": "# ─── Auto-increment VITE_VERSION for rtk-query ──────────────────────────────\n#\n# If any staged file inside apps/rtk-qu"
  },
  {
    "path": ".husky/pre-push",
    "chars": 3250,
    "preview": "#!/usr/bin/env sh\n\n# This script runs automatically before every \"git push\".\n# If any build fails, the push is cancelled"
  },
  {
    "path": ".prettierignore",
    "chars": 66,
    "preview": "node_modules\ndist\nbuild\n.next\n.nuxt\ncoverage\n*.log\npnpm-lock.yaml\n"
  },
  {
    "path": ".prettierrc",
    "chars": 184,
    "preview": "{\n  \"singleQuote\": true,\n  \"tabWidth\": 2,\n  \"trailingComma\": \"es5\",\n  \"bracketSameLine\": true,\n  \"arrowParens\": \"always\""
  },
  {
    "path": "CONTRIBUTING.md",
    "chars": 2580,
    "preview": "> [!NOTE]\n> We prefer English language for all communication.\n\n## Creating an issue\n\nBefore creating an issue please ens"
  },
  {
    "path": "FRONTEND_API_CHANGES.md",
    "chars": 7526,
    "preview": "# Frontend API Changes - January 27-29, 2026\n\nThis document summarizes the API changes from the last 5 commits that requ"
  },
  {
    "path": "README.md",
    "chars": 2560,
    "preview": "[Figma](https://www.figma.com/design/AxTPd4AS8oAgdEF4dDgLis/MusicFun?node-id=9-353&p=f&t=I0svXbRE8kPWOUFB-0) • [ApiHub]("
  },
  {
    "path": "apps/nextjs/.gitignore",
    "chars": 486,
    "preview": "# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.\n\n# dependencies\n/node_modules\n/.pn"
  },
  {
    "path": "apps/nextjs/README.md",
    "chars": 1450,
    "preview": "This is a [Next.js](https://nextjs.org) project bootstrapped with [`create-next-app`](https://nextjs.org/docs/app/api-re"
  },
  {
    "path": "apps/nextjs/eslint.config.mjs",
    "chars": 380,
    "preview": "import { FlatCompat } from '@eslint/eslintrc'\nimport { dirname } from 'path'\nimport { fileURLToPath } from 'url'\n\nconst "
  },
  {
    "path": "apps/nextjs/next.config.ts",
    "chars": 130,
    "preview": "import type { NextConfig } from 'next'\n\nconst nextConfig: NextConfig = {\n  /* config options here */\n}\n\nexport default n"
  },
  {
    "path": "apps/nextjs/package.json",
    "chars": 505,
    "preview": "{\n  \"name\": \"musicfun-nextjs\",\n  \"version\": \"0.1.0\",\n  \"private\": true,\n  \"scripts\": {\n    \"dev\": \"NODE_OPTIONS='--inspe"
  },
  {
    "path": "apps/nextjs/src/app/actions/auth/logout.action.tsx",
    "chars": 322,
    "preview": "'use server'\nimport { cookies } from 'next/headers'\n\nexport async function logout() {\n  const cookieStore = await cookie"
  },
  {
    "path": "apps/nextjs/src/app/api/oauth/callback/route.ts",
    "chars": 808,
    "preview": "import { cookies } from 'next/headers'\nimport { NextResponse } from 'next/server'\n\nimport { authApi } from '@/shared/api"
  },
  {
    "path": "apps/nextjs/src/app/globals.css",
    "chars": 608,
    "preview": ":root {\n  --background: #ffffff;\n  --foreground: #171717;\n}\n\n@media (prefers-color-scheme: dark) {\n  :root {\n    --backg"
  },
  {
    "path": "apps/nextjs/src/app/layout.tsx",
    "chars": 639,
    "preview": "import './globals.css'\n\nimport type { Metadata } from 'next'\nimport { Geist, Geist_Mono } from 'next/font/google'\n\nconst"
  },
  {
    "path": "apps/nextjs/src/app/page.module.css",
    "chars": 2747,
    "preview": ".page {\n  --gray-rgb: 0, 0, 0;\n  --gray-alpha-200: rgba(var(--gray-rgb), 0.08);\n  --gray-alpha-100: rgba(var(--gray-rgb)"
  },
  {
    "path": "apps/nextjs/src/app/page.tsx",
    "chars": 514,
    "preview": "import { UserBlock } from '@/features/auth/ui/UserBlock'\nimport { tracksApi } from '@/shared/api/tracks/tracksApi'\n\nimpo"
  },
  {
    "path": "apps/nextjs/src/app/profile/page.tsx",
    "chars": 498,
    "preview": "import { cookies } from 'next/headers'\n\nimport { authApi } from '@/shared/api/auth-api'\nimport { MeResponseResponse } fr"
  },
  {
    "path": "apps/nextjs/src/app/redirect/page.tsx",
    "chars": 488,
    "preview": "import { cookies } from 'next/headers'\nimport { redirect } from 'next/navigation'\n\nimport { authApi } from '@/shared/api"
  },
  {
    "path": "apps/nextjs/src/features/auth/ui/Login/Login.tsx",
    "chars": 218,
    "preview": "import { authApi } from '@/shared/api/auth-api'\nimport { redirectAfterOauthUri } from '@/shared/api/base'\n\nexport const "
  },
  {
    "path": "apps/nextjs/src/features/auth/ui/Logout/Logout.tsx",
    "chars": 318,
    "preview": "'use client'\nimport { useRouter } from 'next/navigation'\n\nimport { logout } from '@/app/actions/auth/logout.action'\n\nexp"
  },
  {
    "path": "apps/nextjs/src/features/auth/ui/MeInfo/MeInfo.tsx",
    "chars": 270,
    "preview": "import { Logout } from '@/features/auth/ui/Logout/Logout'\nimport { authApi } from '@/shared/api/auth-api'\n\nexport const "
  },
  {
    "path": "apps/nextjs/src/features/auth/ui/UserBlock.tsx",
    "chars": 467,
    "preview": "import { Login } from '@/features/auth/ui/Login/Login'\nimport { MeInfo } from '@/features/auth/ui/MeInfo/MeInfo'\nimport "
  },
  {
    "path": "apps/nextjs/src/middleware.ts",
    "chars": 441,
    "preview": "import { NextRequest, NextResponse } from 'next/server'\n\nimport { reauthMiddleware } from '@/reauth-middleware'\n\nexport "
  },
  {
    "path": "apps/nextjs/src/reauth-middleware.ts",
    "chars": 1539,
    "preview": "import { NextRequest, NextResponse } from 'next/server'\n\nimport { authApi } from '@/shared/api/auth-api'\nimport { create"
  },
  {
    "path": "apps/nextjs/src/shared/api/auth-api.ts",
    "chars": 2547,
    "preview": "import { cookies } from 'next/headers'\n\nimport { baseUrl, jsonHeaders } from '@/shared/api/base'\n\nimport type {\n  AuthTo"
  },
  {
    "path": "apps/nextjs/src/shared/api/authApi.types.ts",
    "chars": 463,
    "preview": "export type MeResponseResponse = {\n  userId: string\n  login: string\n}\n\nexport type AuthTokensResponse = {\n  refreshToken"
  },
  {
    "path": "apps/nextjs/src/shared/api/base.ts",
    "chars": 348,
    "preview": "export const baseUrl = process.env.BASE_URL!\nexport const apiKey = process.env.API_KEY!\n\nexport const jsonHeaders = {\n  "
  },
  {
    "path": "apps/nextjs/src/shared/api/tracks/tracksApi.ts",
    "chars": 4139,
    "preview": "import { baseUrl, formHeaders, jsonHeaders } from '@/shared/api/base'\nimport { Nullable } from '@/shared/common.types'\n\n"
  },
  {
    "path": "apps/nextjs/src/shared/api/tracks/tracksApi.types.ts",
    "chars": 1983,
    "preview": "import { Meta, Nullable } from '../../common/types/common.types'\nimport { CurrentUserReaction } from '../../common/types"
  },
  {
    "path": "apps/nextjs/src/shared/common.types.ts",
    "chars": 35,
    "preview": "export type Nullable<T> = T | null\n"
  },
  {
    "path": "apps/nextjs/src/shared/utils/cookieHelpers.ts",
    "chars": 753,
    "preview": "// src/shared/utils/cookieHelpers.ts\n\nimport { getJwtExpirationMaxAge } from '@/shared/utils/jwt-util'\n\nexport interface"
  },
  {
    "path": "apps/nextjs/src/shared/utils/jwt-util.ts",
    "chars": 1226,
    "preview": "// src/shared/utils/jwtUtils.ts\n\n/**\n * Распарсить payload JWT и вернуть поле exp\n * @throws Error если формат токена не"
  },
  {
    "path": "apps/nextjs/tsconfig.json",
    "chars": 602,
    "preview": "{\n  \"compilerOptions\": {\n    \"target\": \"ES2017\",\n    \"lib\": [\"dom\", \"dom.iterable\", \"esnext\"],\n    \"allowJs\": true,\n    "
  },
  {
    "path": "apps/react-effector-fsd/.gitignore",
    "chars": 323,
    "preview": "# Logs\nlogs\n*.log\nnpm-debug.log*\nyarn-debug.log*\nyarn-error.log*\npnpm-debug.log*\nlerna-debug.log*\n\nnode_modules\ndist\ndis"
  },
  {
    "path": "apps/react-effector-fsd/README.md",
    "chars": 1779,
    "preview": "# Welcome to React Router!\n\nA modern, production-ready template for building full-stack React applications using React R"
  },
  {
    "path": "apps/react-effector-fsd/eslint.config.js",
    "chars": 621,
    "preview": "import js from '@eslint/js'\nimport { defineConfig, globalIgnores } from 'eslint/config'\nimport reactHooks from 'eslint-p"
  },
  {
    "path": "apps/react-effector-fsd/index.html",
    "chars": 1196,
    "preview": "<!doctype html>\n<html lang=\"en\">\n  <head>\n    <meta charset=\"UTF-8\" />\n    <link rel=\"icon\" type=\"image/svg+xml\" href=\"/"
  },
  {
    "path": "apps/react-effector-fsd/package.json",
    "chars": 1371,
    "preview": "{\n  \"name\": \"react-effector-fsd\",\n  \"private\": true,\n  \"version\": \"0.0.1\",\n  \"type\": \"module\",\n  \"scripts\": {\n    \"dev\":"
  },
  {
    "path": "apps/react-effector-fsd/src/app/App.tsx",
    "chars": 452,
    "preview": "import '@/app/styles/fonts.css'\nimport '@/app/styles/variables.css'\nimport '@/app/styles/reset.css'\nimport '@/app/styles"
  },
  {
    "path": "apps/react-effector-fsd/src/app/main.tsx",
    "chars": 499,
    "preview": "import '@/app/styles/fonts.css'\nimport '@/app/styles/variables.css'\nimport '@/app/styles/reset.css'\nimport '@/app/styles"
  },
  {
    "path": "apps/react-effector-fsd/src/app/model/init.ts",
    "chars": 215,
    "preview": "import { createEvent, sample } from 'effector'\n\nimport { initApiClientFx } from '@/features/auth/model/model.ts'\n\nexport"
  },
  {
    "path": "apps/react-effector-fsd/src/app/routes/Routing.tsx",
    "chars": 784,
    "preview": "import { Route, Routes } from 'react-router'\n\nimport { OAuthCallback } from '@/pages/auth/OAuthRedirect/OAuthCallback.ts"
  },
  {
    "path": "apps/react-effector-fsd/src/app/routes/index.ts",
    "chars": 36,
    "preview": "export { Routing } from './Routing'\n"
  },
  {
    "path": "apps/react-effector-fsd/src/app/styles/fonts.css",
    "chars": 1169,
    "preview": "/*\n  source: https://gwfh.mranftl.com/fonts/lato?subsets=latin\n*/\n\n/* lato-regular - latin */\n@font-face {\n  font-family"
  },
  {
    "path": "apps/react-effector-fsd/src/app/styles/global.css",
    "chars": 453,
    "preview": ":root {\n  font-family: Lato, sans-serif;\n  font-weight: 400;\n  -webkit-font-smoothing: antialiased;\n  -moz-osx-font-smoo"
  },
  {
    "path": "apps/react-effector-fsd/src/app/styles/reset.css",
    "chars": 1187,
    "preview": "/* Modern CSS Reset: https://piccalil.li/blog/a-more-modern-css-reset */\n\n/* Box sizing rules */\n*,\n*::before,\n*::after "
  },
  {
    "path": "apps/react-effector-fsd/src/app/styles/variables.css",
    "chars": 1000,
    "preview": ":root {\n  /*\n  * Colors\n  */\n  --color-accent: #ff38b6;\n  --color-disabled: #858585;\n  --color-outline-focus: #1a75f5;\n\n"
  },
  {
    "path": "apps/react-effector-fsd/src/features/auth/api/login.ts",
    "chars": 373,
    "preview": "import { api } from '@/shared/api/client'\n\nimport type { LoginRequestPayload, RefreshOutput } from '../model/auth-api.ty"
  },
  {
    "path": "apps/react-effector-fsd/src/features/auth/api/logout.ts",
    "chars": 174,
    "preview": "import { api } from '@/shared/api/client'\n\nexport const logoutApi = async (refreshToken: string) => {\n  await api().POST"
  },
  {
    "path": "apps/react-effector-fsd/src/features/auth/api/me.ts",
    "chars": 212,
    "preview": "import { api } from '@/shared/api/client'\n\nimport type { User } from '../model/user.types'\n\nexport const meApi = async ("
  },
  {
    "path": "apps/react-effector-fsd/src/features/auth/index.ts",
    "chars": 140,
    "preview": "export { getOauthRedirectUrl } from './model/auth-api.types'\nexport { $me, loginFx, logoutFx } from './model/model.ts'\ne"
  },
  {
    "path": "apps/react-effector-fsd/src/features/auth/model/auth-api.types.ts",
    "chars": 604,
    "preview": "import { getClientConfig } from '@/shared/api/client.ts'\nimport type { components } from '@/shared/api/schema.ts'\n\nexpor"
  },
  {
    "path": "apps/react-effector-fsd/src/features/auth/model/model.ts",
    "chars": 2508,
    "preview": "import { createEffect, createStore, sample } from 'effector'\nimport { toast } from 'react-toastify'\n\nimport { setClientC"
  },
  {
    "path": "apps/react-effector-fsd/src/features/auth/model/user.types.ts",
    "chars": 121,
    "preview": "import type { components } from '@/shared/api/schema.ts'\n\nexport type User = components['schemas']['GetMeOutput'] | null"
  },
  {
    "path": "apps/react-effector-fsd/src/features/auth/ui/LoginButtonAndModal/LoginButtonAndModal.module.css",
    "chars": 433,
    "preview": ".dialog {\n  width: 376px;\n  padding-bottom: 22px;\n}\n\n.content {\n  display: flex;\n  flex-direction: column;\n  gap: 32px;\n"
  },
  {
    "path": "apps/react-effector-fsd/src/features/auth/ui/LoginButtonAndModal/LoginButtonAndModal.tsx",
    "chars": 2443,
    "preview": "import clsx from 'clsx'\nimport { useUnit } from 'effector-react'\nimport { useState } from 'react'\n\nimport { getOauthRedi"
  },
  {
    "path": "apps/react-effector-fsd/src/features/auth/ui/LoginButtonAndModal/index.ts",
    "chars": 60,
    "preview": "export { LoginButtonAndModal } from './LoginButtonAndModal'\n"
  },
  {
    "path": "apps/react-effector-fsd/src/features/auth/ui/ProfileDropdownMenu/ProfileDropdownMenu.module.css",
    "chars": 217,
    "preview": ".trigger {\n  cursor: pointer;\n  display: flex;\n  gap: 8px;\n  align-items: center;\n}\n\n.avatar {\n  overflow: hidden;\n  wid"
  },
  {
    "path": "apps/react-effector-fsd/src/features/auth/ui/ProfileDropdownMenu/ProfileDropdownMenu.stories.tsx",
    "chars": 458,
    "preview": "import type { Meta, StoryObj } from '@storybook/react-vite'\n\nimport { ProfileDropdownMenu } from './ProfileDropdownMenu'"
  },
  {
    "path": "apps/react-effector-fsd/src/features/auth/ui/ProfileDropdownMenu/ProfileDropdownMenu.tsx",
    "chars": 1338,
    "preview": "import { useUnit } from 'effector-react'\nimport { Link } from 'react-router'\n\nimport { $me, logoutFx } from '@/features/"
  },
  {
    "path": "apps/react-effector-fsd/src/features/auth/ui/ProfileDropdownMenu/index.ts",
    "chars": 38,
    "preview": "export * from './ProfileDropdownMenu'\n"
  },
  {
    "path": "apps/react-effector-fsd/src/features/auth/ui/index.ts",
    "chars": 76,
    "preview": "export * from './LoginButtonAndModal'\nexport * from './ProfileDropdownMenu'\n"
  },
  {
    "path": "apps/react-effector-fsd/src/pages/auth/OAuthRedirect/OAuthCallback.module.css",
    "chars": 164,
    "preview": ".title {\n  text-align: center;\n  font-size: 250px;\n  margin: 0;\n}\n\n.subtitle {\n  text-align: center;\n  font-size: 50px;\n"
  },
  {
    "path": "apps/react-effector-fsd/src/pages/auth/OAuthRedirect/OAuthCallback.tsx",
    "chars": 405,
    "preview": "import { useEffect } from 'react'\n\nexport const OAuthCallback = () => {\n  useEffect(() => {\n    const url = new URL(wind"
  },
  {
    "path": "apps/react-effector-fsd/src/pages/home/Home.tsx",
    "chars": 66,
    "preview": "export function Home() {\n  return <div>Musicfun home page</div>\n}\n"
  },
  {
    "path": "apps/react-effector-fsd/src/pages/home/index.ts",
    "chars": 30,
    "preview": "export { Home } from './Home'\n"
  },
  {
    "path": "apps/react-effector-fsd/src/pages/user/UserPage.tsx",
    "chars": 98,
    "preview": "export const UserPage = () => {\n  return (\n    <main>\n      <div>UserPage</div>\n    </main>\n  )\n}\n"
  },
  {
    "path": "apps/react-effector-fsd/src/pages/user/index.ts",
    "chars": 38,
    "preview": "export { UserPage } from './UserPage'\n"
  },
  {
    "path": "apps/react-effector-fsd/src/shared/api/client.ts",
    "chars": 4468,
    "preview": "import createClient, { type Middleware } from 'openapi-fetch'\n\nimport type { paths } from './schema.ts'\n\nconst config = "
  },
  {
    "path": "apps/react-effector-fsd/src/shared/api/schema.ts",
    "chars": 71914,
    "preview": "/**\n * This file was auto-generated by openapi-typescript.\n * Do not make direct changes to the file.\n */\n\nexport interf"
  },
  {
    "path": "apps/react-effector-fsd/src/shared/api/utils/json-api-error.ts",
    "chars": 1574,
    "preview": "export interface JsonApiError {\n  status: string\n  code?: string | number\n  title?: string\n  detail?: string\n  source?: "
  },
  {
    "path": "apps/react-effector-fsd/src/shared/api/utils/request-wrapper.ts",
    "chars": 852,
    "preview": "// types/api.ts\n\nimport { type ExtractError } from './json-api-error.ts'\n\n//--------------------------------------------"
  },
  {
    "path": "apps/react-effector-fsd/src/shared/components/AudioPlayer/AudioPlayer.module.css",
    "chars": 1447,
    "preview": ".player {\n  display: flex;\n  gap: 16px;\n  align-items: center;\n  justify-content: space-between;\n\n  width: 100%;\n  min-h"
  },
  {
    "path": "apps/react-effector-fsd/src/shared/components/AudioPlayer/AudioPlayer.stories.tsx",
    "chars": 1200,
    "preview": "import type { Meta } from '@storybook/react-vite'\nimport { useState } from 'react'\n\nimport { AudioPlayer } from './Audio"
  },
  {
    "path": "apps/react-effector-fsd/src/shared/components/AudioPlayer/AudioPlayer.tsx",
    "chars": 4395,
    "preview": "import { clsx } from 'clsx'\nimport { type ComponentProps, useRef, useState } from 'react'\n\nimport {\n  PauseIcon,\n  PlayI"
  },
  {
    "path": "apps/react-effector-fsd/src/shared/components/AudioPlayer/index.ts",
    "chars": 34,
    "preview": "export * from './AudioPlayer.tsx'\n"
  },
  {
    "path": "apps/react-effector-fsd/src/shared/components/Autocomplete/Autocomplete.module.css",
    "chars": 3862,
    "preview": ".container {\n  position: relative;\n  display: flex;\n  flex-direction: column;\n  width: 100%;\n}\n\n.label {\n  font-size: va"
  },
  {
    "path": "apps/react-effector-fsd/src/shared/components/Autocomplete/Autocomplete.stories.tsx",
    "chars": 12120,
    "preview": "import type { Meta, StoryObj } from '@storybook/react-vite'\nimport { useState } from 'react'\n\nimport { Button } from '.."
  },
  {
    "path": "apps/react-effector-fsd/src/shared/components/Autocomplete/Autocomplete.tsx",
    "chars": 6995,
    "preview": "import { clsx } from 'clsx'\nimport {\n  type ComponentProps,\n  type KeyboardEvent,\n  type ReactNode,\n  useEffect,\n  useRe"
  },
  {
    "path": "apps/react-effector-fsd/src/shared/components/Autocomplete/index.ts",
    "chars": 31,
    "preview": "export * from './Autocomplete'\n"
  },
  {
    "path": "apps/react-effector-fsd/src/shared/components/Button/Button.module.css",
    "chars": 723,
    "preview": ".button {\n  cursor: pointer;\n\n  display: inline-flex;\n  gap: 4px;\n  align-items: center;\n  justify-content: center;\n\n  h"
  },
  {
    "path": "apps/react-effector-fsd/src/shared/components/Button/Button.stories.tsx",
    "chars": 850,
    "preview": "import type { Meta, StoryObj } from '@storybook/react-vite'\n\nimport { Button } from './Button'\n\nconst meta = {\n  title: "
  },
  {
    "path": "apps/react-effector-fsd/src/shared/components/Button/Button.tsx",
    "chars": 696,
    "preview": "import { clsx } from 'clsx'\nimport type { ComponentProps, ElementType } from 'react'\n\nimport s from './Button.module.css"
  },
  {
    "path": "apps/react-effector-fsd/src/shared/components/Button/index.ts",
    "chars": 25,
    "preview": "export * from './Button'\n"
  },
  {
    "path": "apps/react-effector-fsd/src/shared/components/Card/Card.module.css",
    "chars": 105,
    "preview": ".card {\n  display: flex;\n  flex-direction: column;\n  padding: 8px;\n  background: var(--color-bg-card);\n}\n"
  },
  {
    "path": "apps/react-effector-fsd/src/shared/components/Card/Card.stories.tsx",
    "chars": 861,
    "preview": "import type { Meta, StoryObj } from '@storybook/react-vite'\n\nimport { Typography } from '../Typography'\nimport { Card } "
  },
  {
    "path": "apps/react-effector-fsd/src/shared/components/Card/Card.tsx",
    "chars": 516,
    "preview": "import { clsx } from 'clsx'\nimport type { ComponentProps, ElementType, ReactNode } from 'react'\n\nimport s from './Card.m"
  },
  {
    "path": "apps/react-effector-fsd/src/shared/components/Card/index.ts",
    "chars": 23,
    "preview": "export * from './Card'\n"
  },
  {
    "path": "apps/react-effector-fsd/src/shared/components/Dialog/Dialog.module.css",
    "chars": 1585,
    "preview": ".backdrop {\n  position: fixed;\n  z-index: 1;\n  inset: 0;\n\n  display: flex;\n  align-items: center;\n  justify-content: cen"
  },
  {
    "path": "apps/react-effector-fsd/src/shared/components/Dialog/Dialog.stories.tsx",
    "chars": 5447,
    "preview": "import type { Meta } from '@storybook/react-vite'\nimport { useState } from 'react'\n\nimport { Button } from '../Button'\ni"
  },
  {
    "path": "apps/react-effector-fsd/src/shared/components/Dialog/Dialog.tsx",
    "chars": 2669,
    "preview": "import { clsx } from 'clsx'\nimport { createContext, type ReactNode, use, useEffect } from 'react'\nimport { createPortal "
  },
  {
    "path": "apps/react-effector-fsd/src/shared/components/Dialog/index.ts",
    "chars": 25,
    "preview": "export * from './Dialog'\n"
  },
  {
    "path": "apps/react-effector-fsd/src/shared/components/DropdownMenu/DropdownMenu.module.css",
    "chars": 2190,
    "preview": ".container {\n  position: relative;\n  display: inline-block;\n}\n\n.trigger {\n  cursor: pointer;\n\n  display: flex;\n  align-i"
  },
  {
    "path": "apps/react-effector-fsd/src/shared/components/DropdownMenu/DropdownMenu.stories.tsx",
    "chars": 8008,
    "preview": "import type { Meta, StoryObj } from '@storybook/react-vite'\n\nimport { CreateIcon, MoreIcon, PlusIcon } from '@/shared/ic"
  },
  {
    "path": "apps/react-effector-fsd/src/shared/components/DropdownMenu/DropdownMenu.tsx",
    "chars": 8187,
    "preview": "import { clsx } from 'clsx'\nimport {\n  type ComponentProps,\n  createContext,\n  type ElementType,\n  type ReactNode,\n  use"
  },
  {
    "path": "apps/react-effector-fsd/src/shared/components/DropdownMenu/index.ts",
    "chars": 31,
    "preview": "export * from './DropdownMenu'\n"
  },
  {
    "path": "apps/react-effector-fsd/src/shared/components/Hashtag/Tag.module.css",
    "chars": 821,
    "preview": ".hashtag {\n  cursor: pointer;\n\n  display: inline-flex;\n  align-items: center;\n  justify-content: center;\n\n  min-width: 7"
  },
  {
    "path": "apps/react-effector-fsd/src/shared/components/Hashtag/Tag.stories.tsx",
    "chars": 851,
    "preview": "import type { Meta, StoryObj } from '@storybook/react-vite'\n\nimport { Tag } from './Tag.tsx'\n\nconst meta = {\n  title: 'C"
  },
  {
    "path": "apps/react-effector-fsd/src/shared/components/Hashtag/Tag.tsx",
    "chars": 593,
    "preview": "import { clsx } from 'clsx'\nimport type { ComponentProps, ElementType } from 'react'\n\nimport s from './Tag.module.css'\n\n"
  },
  {
    "path": "apps/react-effector-fsd/src/shared/components/Hashtag/index.ts",
    "chars": 26,
    "preview": "export * from './Tag.tsx'\n"
  },
  {
    "path": "apps/react-effector-fsd/src/shared/components/IconButton/IconButton.module.css",
    "chars": 484,
    "preview": ".button {\n  cursor: pointer;\n\n  display: flex;\n  align-items: center;\n  justify-content: center;\n\n  width: 32px;\n  heigh"
  },
  {
    "path": "apps/react-effector-fsd/src/shared/components/IconButton/IconButton.stories.tsx",
    "chars": 1481,
    "preview": "import type { Meta, StoryObj } from '@storybook/react-vite'\n\nimport {\n  DownloadIcon,\n  HomeIcon,\n  LikeIcon,\n  MoreIcon"
  },
  {
    "path": "apps/react-effector-fsd/src/shared/components/IconButton/IconButton.tsx",
    "chars": 405,
    "preview": "import { clsx } from 'clsx'\nimport type { ComponentProps } from 'react'\n\nimport s from './IconButton.module.css'\n\ntype I"
  },
  {
    "path": "apps/react-effector-fsd/src/shared/components/IconButton/index.ts",
    "chars": 29,
    "preview": "export * from './IconButton'\n"
  },
  {
    "path": "apps/react-effector-fsd/src/shared/components/ImageUploader/ImageUploader.module.css",
    "chars": 2191,
    "preview": ".container {\n  width: 100%;\n}\n\n.dropZone {\n  cursor: pointer;\n\n  position: relative;\n\n  display: flex;\n  align-items: ce"
  },
  {
    "path": "apps/react-effector-fsd/src/shared/components/ImageUploader/ImageUploader.stories.tsx",
    "chars": 2147,
    "preview": "import type { Meta, StoryObj } from '@storybook/react-vite'\n\nimport { ImageUploader } from './ImageUploader'\n\nconst meta"
  },
  {
    "path": "apps/react-effector-fsd/src/shared/components/ImageUploader/ImageUploader.tsx",
    "chars": 4037,
    "preview": "import { clsx } from 'clsx'\nimport { type ChangeEvent, type DragEvent, useRef, useState } from 'react'\n\nimport { ImageUp"
  },
  {
    "path": "apps/react-effector-fsd/src/shared/components/ImageUploader/index.ts",
    "chars": 32,
    "preview": "export * from './ImageUploader'\n"
  },
  {
    "path": "apps/react-effector-fsd/src/shared/components/Pagination/Pagination.module.css",
    "chars": 1631,
    "preview": ".pagination {\n  display: flex;\n  gap: 6px;\n  align-items: center;\n}\n\n.navButton {\n  width: 40px;\n  height: 40px;\n  borde"
  },
  {
    "path": "apps/react-effector-fsd/src/shared/components/Pagination/Pagination.stories.tsx",
    "chars": 3594,
    "preview": "import type { Meta, StoryObj } from '@storybook/react-vite'\nimport { useState } from 'react'\n\nimport { Card } from '../C"
  },
  {
    "path": "apps/react-effector-fsd/src/shared/components/Pagination/Pagination.tsx",
    "chars": 3289,
    "preview": "import { clsx } from 'clsx'\nimport type { ComponentProps } from 'react'\n\nimport { KeyboardArrowLeftIcon, KeyboardArrowRi"
  },
  {
    "path": "apps/react-effector-fsd/src/shared/components/Pagination/index.ts",
    "chars": 29,
    "preview": "export * from './Pagination'\n"
  },
  {
    "path": "apps/react-effector-fsd/src/shared/components/Progress/Progress.module.css",
    "chars": 263,
    "preview": ".progress {\n  overflow: hidden;\n\n  width: 100%;\n  height: 4px;\n  border-radius: 4px;\n\n  background-color: var(--color-bo"
  },
  {
    "path": "apps/react-effector-fsd/src/shared/components/Progress/Progress.stories.tsx",
    "chars": 5536,
    "preview": "import type { Meta, StoryObj } from '@storybook/react-vite'\nimport { useState } from 'react'\n\nimport { Button } from '.."
  },
  {
    "path": "apps/react-effector-fsd/src/shared/components/Progress/Progress.tsx",
    "chars": 638,
    "preview": "import { clsx } from 'clsx'\nimport type { ComponentProps } from 'react'\n\nimport s from './Progress.module.css'\n\nexport t"
  },
  {
    "path": "apps/react-effector-fsd/src/shared/components/Progress/index.ts",
    "chars": 27,
    "preview": "export * from './Progress'\n"
  },
  {
    "path": "apps/react-effector-fsd/src/shared/components/ReactionButtons/ReactionButtons.module.css",
    "chars": 640,
    "preview": ".container {\n  display: flex;\n  gap: 8px;\n  align-items: start;\n}\n\n.button {\n  width: 28px;\n  height: 28px;\n  padding: 0"
  },
  {
    "path": "apps/react-effector-fsd/src/shared/components/ReactionButtons/ReactionButtons.stories.tsx",
    "chars": 3367,
    "preview": "import type { Meta, StoryObj } from '@storybook/react-vite'\nimport { useState } from 'react'\n\nimport { Card } from '../C"
  },
  {
    "path": "apps/react-effector-fsd/src/shared/components/ReactionButtons/ReactionButtons.tsx",
    "chars": 1922,
    "preview": "import { clsx } from 'clsx'\n\nimport type { ReactionValue } from '@/shared/api/schema.ts'\nimport { DislikeIcon, LikeIcon,"
  },
  {
    "path": "apps/react-effector-fsd/src/shared/components/ReactionButtons/index.ts",
    "chars": 34,
    "preview": "export * from './ReactionButtons'\n"
  },
  {
    "path": "apps/react-effector-fsd/src/shared/components/SearchField/SearchField.module.css",
    "chars": 726,
    "preview": ".inputWrapper {\n  position: relative;\n  display: flex;\n  align-items: center;\n}\n\n.searchIcon {\n  pointer-events: none;\n\n"
  },
  {
    "path": "apps/react-effector-fsd/src/shared/components/SearchField/SearchField.stories.tsx",
    "chars": 424,
    "preview": "import type { Meta, StoryObj } from '@storybook/react-vite'\n\nimport { SearchField } from './SearchField'\n\nconst meta = {"
  },
  {
    "path": "apps/react-effector-fsd/src/shared/components/SearchField/SearchField.tsx",
    "chars": 604,
    "preview": "import { clsx } from 'clsx'\nimport type { ComponentProps, ReactNode } from 'react'\n\nimport { SearchIcon } from '@/shared"
  },
  {
    "path": "apps/react-effector-fsd/src/shared/components/SearchField/index.ts",
    "chars": 30,
    "preview": "export * from './SearchField'\n"
  },
  {
    "path": "apps/react-effector-fsd/src/shared/components/Select/Select.module.css",
    "chars": 1713,
    "preview": ".container {\n  display: flex;\n  flex-direction: column;\n  width: 100%;\n}\n\n.selectWrapper {\n  position: relative;\n  width"
  },
  {
    "path": "apps/react-effector-fsd/src/shared/components/Select/Select.stories.tsx",
    "chars": 3916,
    "preview": "import type { Meta, StoryObj } from '@storybook/react-vite'\nimport { useState } from 'react'\n\nimport { Select } from './"
  },
  {
    "path": "apps/react-effector-fsd/src/shared/components/Select/Select.tsx",
    "chars": 1605,
    "preview": "import { clsx } from 'clsx'\nimport type { ComponentProps, ReactNode } from 'react'\n\nimport { ArrowDownIcon } from '@/sha"
  },
  {
    "path": "apps/react-effector-fsd/src/shared/components/Select/index.ts",
    "chars": 25,
    "preview": "export * from './Select'\n"
  },
  {
    "path": "apps/react-effector-fsd/src/shared/components/SortSelect/Select.tsx",
    "chars": 1517,
    "preview": "import { clsx } from 'clsx'\nimport type { ComponentProps, ReactNode } from 'react'\n\nimport { ArrowDownIcon } from '@/sha"
  },
  {
    "path": "apps/react-effector-fsd/src/shared/components/Table/Table.module.css",
    "chars": 966,
    "preview": ".table {\n  table-layout: fixed;\n  border-collapse: collapse;\n  width: 100%;\n  background: transparent;\n}\n\n.tableHead {\n "
  },
  {
    "path": "apps/react-effector-fsd/src/shared/components/Table/Table.stories.tsx",
    "chars": 2862,
    "preview": "import type { Meta, StoryObj } from '@storybook/react-vite'\n\nimport { ReactionButtons } from '../ReactionButtons'\nimport"
  },
  {
    "path": "apps/react-effector-fsd/src/shared/components/Table/Table.tsx",
    "chars": 2006,
    "preview": "import { clsx } from 'clsx'\nimport type { ComponentProps, ReactNode } from 'react'\n\nimport s from './Table.module.css'\n\n"
  },
  {
    "path": "apps/react-effector-fsd/src/shared/components/Table/index.ts",
    "chars": 24,
    "preview": "export * from './Table'\n"
  },
  {
    "path": "apps/react-effector-fsd/src/shared/components/Tabs/Tabs.module.css",
    "chars": 943,
    "preview": ".tabsList {\n  display: flex;\n  width: 100%;\n  border-bottom: 1px solid var(--color-text-secondary);\n}\n\n.tabsTrigger {\n  "
  },
  {
    "path": "apps/react-effector-fsd/src/shared/components/Tabs/Tabs.stories.tsx",
    "chars": 4053,
    "preview": "import type { Meta } from '@storybook/react-vite'\nimport { useState } from 'react'\n\nimport { Button } from '../Button'\ni"
  },
  {
    "path": "apps/react-effector-fsd/src/shared/components/Tabs/Tabs.tsx",
    "chars": 2612,
    "preview": "import { clsx } from 'clsx'\nimport { type ComponentProps, createContext, type ReactNode, use, useState } from 'react'\n\ni"
  },
  {
    "path": "apps/react-effector-fsd/src/shared/components/Tabs/index.ts",
    "chars": 23,
    "preview": "export * from './Tabs'\n"
  },
  {
    "path": "apps/react-effector-fsd/src/shared/components/TagEditor/TagEditor.module.css",
    "chars": 1015,
    "preview": ".container {\n  display: flex;\n  flex-direction: column;\n}\n\n.tagsContainer {\n  display: flex;\n  flex-wrap: wrap;\n  gap: 8"
  },
  {
    "path": "apps/react-effector-fsd/src/shared/components/TagEditor/TagEditor.stories.tsx",
    "chars": 3578,
    "preview": "import type { Meta } from '@storybook/react-vite'\nimport { useState } from 'react'\n\nimport { Card } from '../Card'\nimpor"
  },
  {
    "path": "apps/react-effector-fsd/src/shared/components/TagEditor/TagEditor.tsx",
    "chars": 2602,
    "preview": "import { clsx } from 'clsx'\nimport type { ComponentProps, KeyboardEvent } from 'react'\nimport { useState } from 'react'\n"
  },
  {
    "path": "apps/react-effector-fsd/src/shared/components/TagEditor/index.ts",
    "chars": 28,
    "preview": "export * from './TagEditor'\n"
  },
  {
    "path": "apps/react-effector-fsd/src/shared/components/TextField/TextField.module.css",
    "chars": 1078,
    "preview": ".box {\n  display: flex;\n  flex-direction: column;\n  width: 100%;\n}\n\n.inputWrapper {\n  position: relative;\n  display: fle"
  },
  {
    "path": "apps/react-effector-fsd/src/shared/components/TextField/TextField.stories.tsx",
    "chars": 942,
    "preview": "import type { Meta, StoryObj } from '@storybook/react-vite'\n\nimport { SearchIcon } from '@/shared/icons'\n\nimport { TextF"
  },
  {
    "path": "apps/react-effector-fsd/src/shared/components/TextField/TextField.tsx",
    "chars": 1269,
    "preview": "import { clsx } from 'clsx'\nimport type { ComponentProps, ReactNode } from 'react'\n\nimport { useGetId } from '../../hook"
  },
  {
    "path": "apps/react-effector-fsd/src/shared/components/TextField/index.ts",
    "chars": 28,
    "preview": "export * from './TextField'\n"
  },
  {
    "path": "apps/react-effector-fsd/src/shared/components/Textarea/Textarea.module.css",
    "chars": 795,
    "preview": ".box {\n  display: flex;\n  flex-direction: column;\n  width: 100%;\n}\n\n.textarea {\n  resize: none;\n\n  width: 100%;\n  paddin"
  },
  {
    "path": "apps/react-effector-fsd/src/shared/components/Textarea/Textarea.stories.tsx",
    "chars": 838,
    "preview": "import type { Meta, StoryObj } from '@storybook/react-vite'\n\nimport { Textarea } from './Textarea'\n\nconst meta = {\n  tit"
  },
  {
    "path": "apps/react-effector-fsd/src/shared/components/Textarea/Textarea.tsx",
    "chars": 877,
    "preview": "import { clsx } from 'clsx'\nimport type { ComponentProps, ReactNode } from 'react'\n\nimport { useGetId } from '../../hook"
  },
  {
    "path": "apps/react-effector-fsd/src/shared/components/Textarea/index.ts",
    "chars": 27,
    "preview": "export * from './Textarea'\n"
  },
  {
    "path": "apps/react-effector-fsd/src/shared/components/Typography/Typography.module.css",
    "chars": 884,
    "preview": ".label {\n  font-size: var(--font-size-s);\n  line-height: 1.7;\n  color: var(--color-text-label);\n}\n\n.error {\n  font-size:"
  },
  {
    "path": "apps/react-effector-fsd/src/shared/components/Typography/Typography.stories.tsx",
    "chars": 887,
    "preview": "import type { Meta, StoryObj } from '@storybook/react-vite'\n\nimport { Typography } from './Typography'\n\nconst meta = {\n "
  },
  {
    "path": "apps/react-effector-fsd/src/shared/components/Typography/Typography.tsx",
    "chars": 976,
    "preview": "import clsx from 'clsx'\nimport type { ComponentProps, ElementType } from 'react'\nimport React from 'react'\n\nimport style"
  },
  {
    "path": "apps/react-effector-fsd/src/shared/components/Typography/index.ts",
    "chars": 29,
    "preview": "export * from './Typography'\n"
  },
  {
    "path": "apps/react-effector-fsd/src/shared/components/index.ts",
    "chars": 556,
    "preview": "export * from './AudioPlayer'\nexport * from './Autocomplete'\nexport * from './Button'\nexport * from './Card'\nexport * fr"
  },
  {
    "path": "apps/react-effector-fsd/src/shared/config/config.ts",
    "chars": 178,
    "preview": "export const API_BASE_URL = import.meta.env.VITE_API_BASE_URL\nexport const API_KEY = import.meta.env.VITE_API_KEY\nexport"
  },
  {
    "path": "apps/react-effector-fsd/src/shared/hooks/index.ts",
    "chars": 62,
    "preview": "export * from './useDebounceValue'\nexport * from './useGetId'\n"
  },
  {
    "path": "apps/react-effector-fsd/src/shared/hooks/useDebounceValue.ts",
    "chars": 344,
    "preview": "import { useEffect, useState } from 'react'\n\nexport const useDebounceValue = <T>(value: T, delay: number = 700): [T] => "
  },
  {
    "path": "apps/react-effector-fsd/src/shared/hooks/useGetId.ts",
    "chars": 491,
    "preview": "import { useId } from 'react'\n\n/*\n * Custom hook to get an ID.\n * If an ID is passed from component props, it returns th"
  },
  {
    "path": "apps/react-effector-fsd/src/shared/icons/AddToPlaylistIcon.tsx",
    "chars": 905,
    "preview": "import type { SVGProps } from 'react'\n\nexport const AddToPlaylistIcon = (props: SVGProps<SVGSVGElement>) => (\n  <svg\n   "
  },
  {
    "path": "apps/react-effector-fsd/src/shared/icons/ArrowDownIcon.tsx",
    "chars": 369,
    "preview": "import type { SVGProps } from 'react'\n\nexport const ArrowDownIcon = (props: SVGProps<SVGSVGElement>) => (\n  <svg\n    xml"
  },
  {
    "path": "apps/react-effector-fsd/src/shared/icons/ClockIcon.tsx",
    "chars": 596,
    "preview": "import type { SVGProps } from 'react'\n\nexport const ClockIcon = (props: SVGProps<SVGSVGElement>) => (\n  <svg\n    xmlns=\""
  },
  {
    "path": "apps/react-effector-fsd/src/shared/icons/CreateIcon.tsx",
    "chars": 498,
    "preview": "import type { SVGProps } from 'react'\n\nexport const CreateIcon = (props: SVGProps<SVGSVGElement>) => (\n  <svg\n    width="
  },
  {
    "path": "apps/react-effector-fsd/src/shared/icons/DeleteIcon.tsx",
    "chars": 479,
    "preview": "import type { SVGProps } from 'react'\n\nexport const DeleteIcon = (props: SVGProps<SVGSVGElement>) => (\n  <svg\n    xmlns="
  },
  {
    "path": "apps/react-effector-fsd/src/shared/icons/DislikeIcon.tsx",
    "chars": 822,
    "preview": "import type { SVGProps } from 'react'\n\nexport const DislikeIcon = (props: SVGProps<SVGSVGElement>) => (\n  <svg\n    xmlns"
  },
  {
    "path": "apps/react-effector-fsd/src/shared/icons/DownloadIcon.tsx",
    "chars": 665,
    "preview": "import type { SVGProps } from 'react'\n\nexport const DownloadIcon = (props: SVGProps<SVGSVGElement>) => (\n  <svg\n    xmln"
  },
  {
    "path": "apps/react-effector-fsd/src/shared/icons/EditIcon.tsx",
    "chars": 546,
    "preview": "import { type SVGProps } from 'react'\n\nexport const EditIcon = (props: SVGProps<SVGSVGElement>) => (\n  <svg\n    xmlns=\"h"
  },
  {
    "path": "apps/react-effector-fsd/src/shared/icons/HomeIcon.tsx",
    "chars": 488,
    "preview": "import type { SVGProps } from 'react'\n\nexport const HomeIcon = (props: SVGProps<SVGSVGElement>) => (\n  <svg\n    width=\"3"
  },
  {
    "path": "apps/react-effector-fsd/src/shared/icons/ImageUploadIcon.tsx",
    "chars": 609,
    "preview": "import type { SVGProps } from 'react'\n\nexport const ImageUploadIcon = (props: SVGProps<SVGSVGElement>) => (\n  <svg\n    x"
  },
  {
    "path": "apps/react-effector-fsd/src/shared/icons/KeyboardArrowLeftIcon.tsx",
    "chars": 352,
    "preview": "import type { SVGProps } from 'react'\n\nexport const KeyboardArrowLeftIcon = (props: SVGProps<SVGSVGElement>) => (\n  <svg"
  },
  {
    "path": "apps/react-effector-fsd/src/shared/icons/KeyboardArrowRightIcon.tsx",
    "chars": 299,
    "preview": "import type { SVGProps } from 'react'\n\nexport const KeyboardArrowRightIcon = (props: SVGProps<SVGSVGElement>) => (\n  <sv"
  },
  {
    "path": "apps/react-effector-fsd/src/shared/icons/LibraryIcon.tsx",
    "chars": 823,
    "preview": "import type { SVGProps } from 'react'\n\nexport const LibraryIcon = (props: SVGProps<SVGSVGElement>) => (\n  <svg\n    width"
  },
  {
    "path": "apps/react-effector-fsd/src/shared/icons/LikeIcon.tsx",
    "chars": 765,
    "preview": "import type { SVGProps } from 'react'\n\nexport const LikeIcon = (props: SVGProps<SVGSVGElement>) => (\n  <svg\n    xmlns=\"h"
  },
  {
    "path": "apps/react-effector-fsd/src/shared/icons/LikeIconFill.tsx",
    "chars": 632,
    "preview": "import type { SVGProps } from 'react'\n\nexport const LikeIconFill = (props: SVGProps<SVGSVGElement>) => (\n  <svg\n    xmln"
  },
  {
    "path": "apps/react-effector-fsd/src/shared/icons/LikeInSquareIcon.tsx",
    "chars": 756,
    "preview": "import type { SVGProps } from 'react'\n\nexport const LikeInSquareIcon = (props: SVGProps<SVGSVGElement>) => (\n  <svg\n    "
  },
  {
    "path": "apps/react-effector-fsd/src/shared/icons/LiveWaveIcon/LiveWaveIcon.module.css",
    "chars": 240,
    "preview": ".bar {\n  transform-origin: center bottom;\n  animation: wave 1.2s ease-in-out infinite alternate;\n}\n\n@keyframes wave {\n  "
  },
  {
    "path": "apps/react-effector-fsd/src/shared/icons/LiveWaveIcon/LiveWaveIcon.tsx",
    "chars": 1011,
    "preview": "import type { SVGProps } from 'react'\n\nimport s from './LiveWaveIcon.module.css'\n\nexport const LiveWaveIcon = (props: SV"
  },
  {
    "path": "apps/react-effector-fsd/src/shared/icons/LiveWaveIcon/index.ts",
    "chars": 46,
    "preview": "export { LiveWaveIcon } from './LiveWaveIcon'\n"
  },
  {
    "path": "apps/react-effector-fsd/src/shared/icons/LogoutIcon.tsx",
    "chars": 413,
    "preview": "import { type SVGProps } from 'react'\n\nexport const LogoutIcon = (props: SVGProps<SVGSVGElement>) => (\n  <svg\n    xmlns="
  },
  {
    "path": "apps/react-effector-fsd/src/shared/icons/MoreIcon.tsx",
    "chars": 397,
    "preview": "import type { SVGProps } from 'react'\n\nexport const MoreIcon = (props: SVGProps<SVGSVGElement>) => (\n  <svg\n    xmlns=\"h"
  },
  {
    "path": "apps/react-effector-fsd/src/shared/icons/PauseIcon.tsx",
    "chars": 511,
    "preview": "import type { SVGProps } from 'react'\n\nexport const PauseIcon = (props: SVGProps<SVGSVGElement>) => (\n  <svg\n    xmlns=\""
  },
  {
    "path": "apps/react-effector-fsd/src/shared/icons/PlayIcon.tsx",
    "chars": 481,
    "preview": "import type { SVGProps } from 'react'\n\nexport const PlayIcon = (props: SVGProps<SVGSVGElement>) => (\n  <svg\n    xmlns=\"h"
  },
  {
    "path": "apps/react-effector-fsd/src/shared/icons/PlaylistIcon.tsx",
    "chars": 589,
    "preview": "import type { SVGProps } from 'react'\n\nexport const PlaylistIcon = (props: SVGProps<SVGSVGElement>) => (\n  <svg\n    xmln"
  },
  {
    "path": "apps/react-effector-fsd/src/shared/icons/PlusIcon.tsx",
    "chars": 428,
    "preview": "import type { SVGProps } from 'react'\n\nexport const PlusIcon = (props: SVGProps<SVGSVGElement>) => (\n  <svg\n    xmlns=\"h"
  },
  {
    "path": "apps/react-effector-fsd/src/shared/icons/ProfileIcon.tsx",
    "chars": 643,
    "preview": "import { type SVGProps } from 'react'\n\nexport const ProfileIcon = (props: SVGProps<SVGSVGElement>) => (\n  <svg\n    xmlns"
  },
  {
    "path": "apps/react-effector-fsd/src/shared/icons/RepeatIcon.tsx",
    "chars": 448,
    "preview": "import type { SVGProps } from 'react'\n\nexport const RepeatIcon = (props: SVGProps<SVGSVGElement>) => (\n  <svg\n    xmlns="
  },
  {
    "path": "apps/react-effector-fsd/src/shared/icons/SearchIcon.tsx",
    "chars": 1391,
    "preview": "import type { SVGProps } from 'react'\n\nexport const SearchIcon = (props: SVGProps<SVGSVGElement>) => (\n  <svg\n    viewBo"
  },
  {
    "path": "apps/react-effector-fsd/src/shared/icons/ShuffleIcon.tsx",
    "chars": 550,
    "preview": "import type { SVGProps } from 'react'\n\nexport const ShuffleIcon = (props: SVGProps<SVGSVGElement>) => (\n  <svg\n    xmlns"
  },
  {
    "path": "apps/react-effector-fsd/src/shared/icons/SkipNextIcon.tsx",
    "chars": 417,
    "preview": "import type { SVGProps } from 'react'\n\nexport const SkipNextIcon = (props: SVGProps<SVGSVGElement>) => (\n  <svg\n    xmln"
  },
  {
    "path": "apps/react-effector-fsd/src/shared/icons/SkipPreviousIcon.tsx",
    "chars": 416,
    "preview": "import type { SVGProps } from 'react'\n\nexport const SkipPreviousIcon = (props: SVGProps<SVGSVGElement>) => (\n  <svg\n    "
  }
]

// ... and 2017 more files (download for full content)

About this extraction

This page contains the full source code of the it-incubator/musicfun-react-all-stacks GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 2217 files (3.0 MB), approximately 932.2k tokens, and a symbol index with 1980 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.

Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.

Copied to clipboard!