From aa334aacbd433c478b3f4ac24ed0ed8f00d46167 Mon Sep 17 00:00:00 2001 From: LuanRT Date: Sun, 6 Nov 2022 03:32:16 -0300 Subject: [PATCH] refactor: clean up, fix & remove outdated code (#228) * dev: refactor and remove redundant code * docs(music): update `Library` API ref * docs: update examples * chore: update lock file --- README.md | 2 +- docs/API/music.md | 26 +- package-lock.json | 2148 ++++++++++------- src/Innertube.ts | 82 +- src/core/AccountManager.ts | 34 +- src/core/Actions.ts | 641 +---- src/core/Feed.ts | 23 +- src/core/FilterableFeed.ts | 3 +- src/core/InteractionManager.ts | 113 +- src/core/Music.ts | 86 +- src/core/OAuth.ts | 1 - src/core/PlaylistManager.ts | 48 +- src/core/Studio.ts | 15 +- src/parser/classes/Grid.ts | 27 +- src/parser/classes/MusicDetailHeader.ts | 4 +- src/parser/classes/MusicResponsiveListItem.ts | 34 +- src/parser/classes/MusicSideAlignedItem.ts | 5 + src/parser/classes/MusicTwoRowItem.ts | 22 +- src/parser/classes/NavigationEndpoint.ts | 234 +- src/parser/classes/PlaylistPanelVideo.ts | 8 +- src/parser/classes/comments/Comment.ts | 6 +- src/parser/classes/comments/CommentThread.ts | 4 +- .../classes/menus/MusicMultiSelectMenuItem.ts | 16 +- src/parser/classes/misc/Author.ts | 10 +- src/parser/index.ts | 57 +- src/parser/youtube/AccountInfo.ts | 4 +- src/parser/youtube/Analytics.ts | 4 +- src/parser/youtube/Channel.ts | 6 +- src/parser/youtube/Comments.ts | 15 +- src/parser/youtube/ItemMenu.ts | 2 +- src/parser/youtube/Library.ts | 6 +- src/parser/youtube/LiveChat.ts | 4 +- src/parser/youtube/NotificationsMenu.ts | 6 +- src/parser/youtube/Playlist.ts | 27 +- src/parser/youtube/Search.ts | 2 +- src/parser/youtube/Settings.ts | 6 +- src/parser/youtube/TimeWatched.ts | 4 +- src/parser/youtube/VideoInfo.ts | 8 +- src/parser/ytmusic/Album.ts | 6 +- src/parser/ytmusic/Artist.ts | 10 +- src/parser/ytmusic/Explore.ts | 6 +- src/parser/ytmusic/HomeFeed.ts | 12 +- src/parser/ytmusic/Library.ts | 431 ++-- src/parser/ytmusic/Playlist.ts | 81 +- src/parser/ytmusic/Recap.ts | 14 +- src/parser/ytmusic/Search.ts | 16 +- src/parser/ytmusic/TrackInfo.ts | 8 +- src/proto/index.ts | 54 +- src/proto/youtube.proto | 12 - src/utils/Utils.ts | 16 +- 50 files changed, 2006 insertions(+), 2403 deletions(-) diff --git a/README.md b/README.md index b6ec6024..034d6ee6 100644 --- a/README.md +++ b/README.md @@ -600,7 +600,7 @@ const button = albums.as(MusicCarouselShelf).header?.more_content; if (button) { // To do that, we can call its navigation endpoint: - const page = await button.endpoint.call(yt.actions, 'YTMUSIC', true); + const page = await button.endpoint.call(yt.actions, { parse: true, client: 'YTMUSIC' }); console.info(page); } ``` diff --git a/docs/API/music.md b/docs/API/music.md index fbe7e0c7..64ac5d6f 100644 --- a/docs/API/music.md +++ b/docs/API/music.md @@ -155,20 +155,26 @@ Retrieves library. Methods & Getters

-- `#getPlaylists(args?)` - - Retrieves the library's playlists. +- `#applyFilter(filter)` + - Applies given filter to the library. -- `#getAlbums(args?)` - - Retrieves the library's albums. +- `#applySortFilter(filter)` + - Applies given sort filter to the library items. -- `#getArtists(args?)` - - Retrieves the library's artists. +- `#getContinuation()` + - Retrieves continuation of the library items. -- `#getSongs(args?)` - - Retrieves the library's songs. +- `#has_continuation` + - Checks if continuation is available. -- `#getRecentActivity(args)` - - Retrieves recent activity. +- `#filters` + - Returns available filters. + +- `#sort_filters` + - Returns available sort filters. + +- `#page` + - Returns original InnerTube response (sanitized).

diff --git a/package-lock.json b/package-lock.json index e916d4c9..c804435e 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "youtubei.js", - "version": "2.3.2" + "version": "2.3.2", "lockfileVersion": 2, "requires": true, "packages": { @@ -58,30 +58,30 @@ } }, "node_modules/@babel/compat-data": { - "version": "7.18.8", - "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.18.8.tgz", - "integrity": "sha512-HSmX4WZPPK3FUxYp7g2T6EyO8j96HlZJlxmKPSh6KAcqwyDrfx7hKjXpAW/0FhFfTJsR0Yt4lAjLI2coMptIHQ==", + "version": "7.20.1", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.20.1.tgz", + "integrity": "sha512-EWZ4mE2diW3QALKvDMiXnbZpRvlj+nayZ112nK93SnhqOtpdsbVD4W+2tEoT3YNBAG9RBR0ISY758ZkOgsn6pQ==", "dev": true, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/core": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.18.6.tgz", - "integrity": "sha512-cQbWBpxcbbs/IUredIPkHiAGULLV8iwgNRMFzvbhEXISp4f3rUUXE5+TIw6KwUWUR3DwyI6gmBRnmAtYaWehwQ==", + "version": "7.20.2", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.20.2.tgz", + "integrity": "sha512-w7DbG8DtMrJcFOi4VrLm+8QM4az8Mo+PuLBKLp2zrYRCow8W/f9xiXm5sN53C8HksCyDQwCKha9JiDoIyPjT2g==", "dev": true, "dependencies": { "@ampproject/remapping": "^2.1.0", "@babel/code-frame": "^7.18.6", - "@babel/generator": "^7.18.6", - "@babel/helper-compilation-targets": "^7.18.6", - "@babel/helper-module-transforms": "^7.18.6", - "@babel/helpers": "^7.18.6", - "@babel/parser": "^7.18.6", - "@babel/template": "^7.18.6", - "@babel/traverse": "^7.18.6", - "@babel/types": "^7.18.6", + "@babel/generator": "^7.20.2", + "@babel/helper-compilation-targets": "^7.20.0", + "@babel/helper-module-transforms": "^7.20.2", + "@babel/helpers": "^7.20.1", + "@babel/parser": "^7.20.2", + "@babel/template": "^7.18.10", + "@babel/traverse": "^7.20.1", + "@babel/types": "^7.20.2", "convert-source-map": "^1.7.0", "debug": "^4.1.0", "gensync": "^1.0.0-beta.2", @@ -106,12 +106,12 @@ } }, "node_modules/@babel/generator": { - "version": "7.18.7", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.18.7.tgz", - "integrity": "sha512-shck+7VLlY72a2w9c3zYWuE1pwOKEiQHV7GTUbSnhyl5eu3i04t30tBY82ZRWrDfo3gkakCFtevExnxbkf2a3A==", + "version": "7.20.2", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.20.2.tgz", + "integrity": "sha512-SD75PMIK6i9H8G/tfGvB4KKl4Nw6Ssos9nGgYwxbgyTP0iX/Z55DveoH86rmUB/YHTQQ+ZC0F7xxaY8l2OF44Q==", "dev": true, "dependencies": { - "@babel/types": "^7.18.7", + "@babel/types": "^7.20.2", "@jridgewell/gen-mapping": "^0.3.2", "jsesc": "^2.5.1" }, @@ -134,14 +134,14 @@ } }, "node_modules/@babel/helper-compilation-targets": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.18.6.tgz", - "integrity": "sha512-vFjbfhNCzqdeAtZflUFrG5YIFqGTqsctrtkZ1D/NB0mDW9TwW3GmmUepYY4G9wCET5rY5ugz4OGTcLd614IzQg==", + "version": "7.20.0", + "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.20.0.tgz", + "integrity": "sha512-0jp//vDGp9e8hZzBc6N/KwA5ZK3Wsm/pfm4CrY7vzegkVxc65SgSn6wYOnwHe9Js9HRQ1YTCKLGPzDtaS3RoLQ==", "dev": true, "dependencies": { - "@babel/compat-data": "^7.18.6", + "@babel/compat-data": "^7.20.0", "@babel/helper-validator-option": "^7.18.6", - "browserslist": "^4.20.2", + "browserslist": "^4.21.3", "semver": "^6.3.0" }, "engines": { @@ -161,22 +161,22 @@ } }, "node_modules/@babel/helper-environment-visitor": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.18.6.tgz", - "integrity": "sha512-8n6gSfn2baOY+qlp+VSzsosjCVGFqWKmDF0cCWOybh52Dw3SEyoWR1KrhMJASjLwIEkkAufZ0xvr+SxLHSpy2Q==", + "version": "7.18.9", + "resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.18.9.tgz", + "integrity": "sha512-3r/aACDJ3fhQ/EVgFy0hpj8oHyHpQc+LPtJoY9SzTThAsStm4Ptegq92vqKoE3vD706ZVFWITnMnxucw+S9Ipg==", "dev": true, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-function-name": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.18.6.tgz", - "integrity": "sha512-0mWMxV1aC97dhjCah5U5Ua7668r5ZmSC2DLfH2EZnf9c3/dHZKiFa5pRLMH5tjSl471tY6496ZWk/kjNONBxhw==", + "version": "7.19.0", + "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.19.0.tgz", + "integrity": "sha512-WAwHBINyrpqywkUH0nTnNgI5ina5TFn85HKS0pbPDfxFfhyR/aNQEn4hGi1P1JyT//I0t4OgXUlofzWILRvS5w==", "dev": true, "dependencies": { - "@babel/template": "^7.18.6", - "@babel/types": "^7.18.6" + "@babel/template": "^7.18.10", + "@babel/types": "^7.19.0" }, "engines": { "node": ">=6.9.0" @@ -207,40 +207,40 @@ } }, "node_modules/@babel/helper-module-transforms": { - "version": "7.18.8", - "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.18.8.tgz", - "integrity": "sha512-che3jvZwIcZxrwh63VfnFTUzcAM9v/lznYkkRxIBGMPt1SudOKHAEec0SIRCfiuIzTcF7VGj/CaTT6gY4eWxvA==", + "version": "7.20.2", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.20.2.tgz", + "integrity": "sha512-zvBKyJXRbmK07XhMuujYoJ48B5yvvmM6+wcpv6Ivj4Yg6qO7NOZOSnvZN9CRl1zz1Z4cKf8YejmCMh8clOoOeA==", "dev": true, "dependencies": { - "@babel/helper-environment-visitor": "^7.18.6", + "@babel/helper-environment-visitor": "^7.18.9", "@babel/helper-module-imports": "^7.18.6", - "@babel/helper-simple-access": "^7.18.6", + "@babel/helper-simple-access": "^7.20.2", "@babel/helper-split-export-declaration": "^7.18.6", - "@babel/helper-validator-identifier": "^7.18.6", - "@babel/template": "^7.18.6", - "@babel/traverse": "^7.18.8", - "@babel/types": "^7.18.8" + "@babel/helper-validator-identifier": "^7.19.1", + "@babel/template": "^7.18.10", + "@babel/traverse": "^7.20.1", + "@babel/types": "^7.20.2" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-plugin-utils": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.18.6.tgz", - "integrity": "sha512-gvZnm1YAAxh13eJdkb9EWHBnF3eAub3XTLCZEehHT2kWxiKVRL64+ae5Y6Ivne0mVHmMYKT+xWgZO+gQhuLUBg==", + "version": "7.20.2", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.20.2.tgz", + "integrity": "sha512-8RvlJG2mj4huQ4pZ+rU9lqKi9ZKiRmuvGuM2HlWmkmgOhbs6zEAw6IEiJ5cQqGbDzGZOhwuOQNtZMi/ENLjZoQ==", "dev": true, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-simple-access": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.18.6.tgz", - "integrity": "sha512-iNpIgTgyAvDQpDj76POqg+YEt8fPxx3yaNBg3S30dxNKm2SWfYhD0TGrK/Eu9wHpUW63VQU894TsTg+GLbUa1g==", + "version": "7.20.2", + "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.20.2.tgz", + "integrity": "sha512-+0woI/WPq59IrqDYbVGfshjT5Dmk/nnbdpcF8SnMhhXObpTq2KNBdLFRFrkVdbDOyUmHBCxzm5FHV1rACIkIbA==", "dev": true, "dependencies": { - "@babel/types": "^7.18.6" + "@babel/types": "^7.20.2" }, "engines": { "node": ">=6.9.0" @@ -258,10 +258,19 @@ "node": ">=6.9.0" } }, + "node_modules/@babel/helper-string-parser": { + "version": "7.19.4", + "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.19.4.tgz", + "integrity": "sha512-nHtDoQcuqFmwYNYPz3Rah5ph2p8PFeFCsZk9A/48dPc/rGocJ5J3hAAZ7pb76VWX3fZKu+uEr/FhH5jLx7umrw==", + "dev": true, + "engines": { + "node": ">=6.9.0" + } + }, "node_modules/@babel/helper-validator-identifier": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.18.6.tgz", - "integrity": "sha512-MmetCkz9ej86nJQV+sFCxoGGrUbU3q02kgLciwkrt9QqEB7cP39oKEY0PakknEO0Gu20SskMRi+AYZ3b1TpN9g==", + "version": "7.19.1", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.19.1.tgz", + "integrity": "sha512-awrNfaMtnHUr653GgGEs++LlAvW6w+DcPrOliSMXWCKo597CwL5Acf/wWdNkf/tfEQE3mjkeD1YOVZOUV/od1w==", "dev": true, "engines": { "node": ">=6.9.0" @@ -277,14 +286,14 @@ } }, "node_modules/@babel/helpers": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.18.6.tgz", - "integrity": "sha512-vzSiiqbQOghPngUYt/zWGvK3LAsPhz55vc9XNN0xAl2gV4ieShI2OQli5duxWHD+72PZPTKAcfcZDE1Cwc5zsQ==", + "version": "7.20.1", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.20.1.tgz", + "integrity": "sha512-J77mUVaDTUJFZ5BpP6mMn6OIl3rEWymk2ZxDBQJUG3P+PbmyMcF3bYWvz0ma69Af1oobDqT/iAsvzhB58xhQUg==", "dev": true, "dependencies": { - "@babel/template": "^7.18.6", - "@babel/traverse": "^7.18.6", - "@babel/types": "^7.18.6" + "@babel/template": "^7.18.10", + "@babel/traverse": "^7.20.1", + "@babel/types": "^7.20.0" }, "engines": { "node": ">=6.9.0" @@ -376,9 +385,9 @@ } }, "node_modules/@babel/parser": { - "version": "7.18.8", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.18.8.tgz", - "integrity": "sha512-RSKRfYX20dyH+elbJK2uqAkVyucL+xXzhqlMD5/ZXx+dAAwpyB7HsvnHe/ZUGOF+xLr5Wx9/JoXVTj6BQE2/oA==", + "version": "7.20.2", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.20.2.tgz", + "integrity": "sha512-afk318kh2uKbo7BEj2QtEi8HVCGrwHUffrYDy7dgVcSa2j9lY3LDjPzcyGdpX7xgm35aWqvciZJ4WKmdF/SxYg==", "dev": true, "bin": { "parser": "bin/babel-parser.js" @@ -535,12 +544,12 @@ } }, "node_modules/@babel/plugin-syntax-typescript": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.18.6.tgz", - "integrity": "sha512-mAWAuq4rvOepWCBid55JuRNvpTNf2UGVgoz4JV0fXEKolsVZDzsa4NqCef758WZJj/GDu0gVGItjKFiClTAmZA==", + "version": "7.20.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.20.0.tgz", + "integrity": "sha512-rd9TkG+u1CExzS4SM1BlMEhMXwFLKVjOAFFCDx9PbX5ycJWDoWMcwdJH9RhkPu1dOgn5TrxLot/Gx6lWFuAUNQ==", "dev": true, "dependencies": { - "@babel/helper-plugin-utils": "^7.18.6" + "@babel/helper-plugin-utils": "^7.19.0" }, "engines": { "node": ">=6.9.0" @@ -550,33 +559,33 @@ } }, "node_modules/@babel/template": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.18.6.tgz", - "integrity": "sha512-JoDWzPe+wgBsTTgdnIma3iHNFC7YVJoPssVBDjiHfNlyt4YcunDtcDOUmfVDfCK5MfdsaIoX9PkijPhjH3nYUw==", + "version": "7.18.10", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.18.10.tgz", + "integrity": "sha512-TI+rCtooWHr3QJ27kJxfjutghu44DLnasDMwpDqCXVTal9RLp3RSYNh4NdBrRP2cQAoG9A8juOQl6P6oZG4JxA==", "dev": true, "dependencies": { "@babel/code-frame": "^7.18.6", - "@babel/parser": "^7.18.6", - "@babel/types": "^7.18.6" + "@babel/parser": "^7.18.10", + "@babel/types": "^7.18.10" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/traverse": { - "version": "7.18.8", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.18.8.tgz", - "integrity": "sha512-UNg/AcSySJYR/+mIcJQDCv00T+AqRO7j/ZEJLzpaYtgM48rMg5MnkJgyNqkzo88+p4tfRvZJCEiwwfG6h4jkRg==", + "version": "7.20.1", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.20.1.tgz", + "integrity": "sha512-d3tN8fkVJwFLkHkBN479SOsw4DMZnz8cdbL/gvuDuzy3TS6Nfw80HuQqhw1pITbIruHyh7d1fMA47kWzmcUEGA==", "dev": true, "dependencies": { "@babel/code-frame": "^7.18.6", - "@babel/generator": "^7.18.7", - "@babel/helper-environment-visitor": "^7.18.6", - "@babel/helper-function-name": "^7.18.6", + "@babel/generator": "^7.20.1", + "@babel/helper-environment-visitor": "^7.18.9", + "@babel/helper-function-name": "^7.19.0", "@babel/helper-hoist-variables": "^7.18.6", "@babel/helper-split-export-declaration": "^7.18.6", - "@babel/parser": "^7.18.8", - "@babel/types": "^7.18.8", + "@babel/parser": "^7.20.1", + "@babel/types": "^7.20.0", "debug": "^4.1.0", "globals": "^11.1.0" }, @@ -594,12 +603,13 @@ } }, "node_modules/@babel/types": { - "version": "7.18.8", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.18.8.tgz", - "integrity": "sha512-qwpdsmraq0aJ3osLJRApsc2ouSJCdnMeZwB0DhbtHAtRpZNZCdlbRnHIgcRKzdE1g0iOGg644fzjOBcdOz9cPw==", + "version": "7.20.2", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.20.2.tgz", + "integrity": "sha512-FnnvsNWgZCr232sqtXggapvlkk/tuwR/qhGzcmxI0GXLCjmPYQPzio2FbdlWuY6y1sHFfQKk+rRbUZ9VStQMog==", "dev": true, "dependencies": { - "@babel/helper-validator-identifier": "^7.18.6", + "@babel/helper-string-parser": "^7.19.4", + "@babel/helper-validator-identifier": "^7.19.1", "to-fast-properties": "^2.0.0" }, "engines": { @@ -612,15 +622,31 @@ "integrity": "sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==", "dev": true }, + "node_modules/@esbuild/linux-loong64": { + "version": "0.14.54", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.14.54.tgz", + "integrity": "sha512-bZBrLAIX1kpWelV0XemxBZllyRmM6vgFQQG2GdNb+r3Fkp0FOh1NJSvekXDs7jq70k4euu1cryLMfU+mTXlEpw==", + "cpu": [ + "loong64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, "node_modules/@eslint/eslintrc": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-1.3.0.tgz", - "integrity": "sha512-UWW0TMTmk2d7hLcWD1/e2g5HDM/HQ3csaLSqXCfqwh4uNDuNqlaKWXmEsL4Cs41Z0KnILNvwbHAah3C2yt06kw==", + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-1.3.3.tgz", + "integrity": "sha512-uj3pT6Mg+3t39fvLrj8iuCIJ38zKO9FpGtJ4BBJebJhEwjoT+KLVNCcHT5QC9NGRIEi7fZ0ZR8YRb884auB4Lg==", "dev": true, "dependencies": { "ajv": "^6.12.4", "debug": "^4.3.2", - "espree": "^9.3.2", + "espree": "^9.4.0", "globals": "^13.15.0", "ignore": "^5.2.0", "import-fresh": "^3.2.1", @@ -630,22 +656,38 @@ }, "engines": { "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" } }, "node_modules/@humanwhocodes/config-array": { - "version": "0.9.5", - "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.9.5.tgz", - "integrity": "sha512-ObyMyWxZiCu/yTisA7uzx81s40xR2fD5Cg/2Kq7G02ajkNubJf6BopgDTmDyc3U7sXpNKM8cYOw7s7Tyr+DnCw==", + "version": "0.11.7", + "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.7.tgz", + "integrity": "sha512-kBbPWzN8oVMLb0hOUYXhmxggL/1cJE6ydvjDIGi9EnAGUyA7cLVKQg+d/Dsm+KZwx2czGHrCmMVLiyg8s5JPKw==", "dev": true, "dependencies": { "@humanwhocodes/object-schema": "^1.2.1", "debug": "^4.1.1", - "minimatch": "^3.0.4" + "minimatch": "^3.0.5" }, "engines": { "node": ">=10.10.0" } }, + "node_modules/@humanwhocodes/module-importer": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz", + "integrity": "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==", + "dev": true, + "engines": { + "node": ">=12.22" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/nzakas" + } + }, "node_modules/@humanwhocodes/object-schema": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-1.2.1.tgz", @@ -677,6 +719,19 @@ "sprintf-js": "~1.0.2" } }, + "node_modules/@istanbuljs/load-nyc-config/node_modules/find-up": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", + "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", + "dev": true, + "dependencies": { + "locate-path": "^5.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/@istanbuljs/load-nyc-config/node_modules/js-yaml": { "version": "3.14.1", "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz", @@ -690,6 +745,45 @@ "js-yaml": "bin/js-yaml.js" } }, + "node_modules/@istanbuljs/load-nyc-config/node_modules/locate-path": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", + "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", + "dev": true, + "dependencies": { + "p-locate": "^4.1.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/@istanbuljs/load-nyc-config/node_modules/p-limit": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", + "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", + "dev": true, + "dependencies": { + "p-try": "^2.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@istanbuljs/load-nyc-config/node_modules/p-locate": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", + "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", + "dev": true, + "dependencies": { + "p-limit": "^2.2.0" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/@istanbuljs/load-nyc-config/node_modules/resolve-from": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", @@ -1045,46 +1139,33 @@ "dev": true }, "node_modules/@jridgewell/trace-mapping": { - "version": "0.3.14", - "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.14.tgz", - "integrity": "sha512-bJWEfQ9lPTvm3SneWwRFVLzrh6nhjwqw7TUFFBEMzwvg7t7PCDenf2lDwqo4NQXzdpgBXyFgDWnQA+2vkruksQ==", + "version": "0.3.17", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.17.tgz", + "integrity": "sha512-MCNzAp77qzKca9+W/+I0+sEpaUnZoeasnghNeVc41VZCEKaCH73Vq3BZZ/SzWIgrqE4H4ceI+p+b6C0mHf9T4g==", "dev": true, "dependencies": { - "@jridgewell/resolve-uri": "^3.0.3", - "@jridgewell/sourcemap-codec": "^1.4.10" + "@jridgewell/resolve-uri": "3.1.0", + "@jridgewell/sourcemap-codec": "1.4.14" } }, "node_modules/@microsoft/tsdoc": { - "version": "0.14.1", - "resolved": "https://registry.npmjs.org/@microsoft/tsdoc/-/tsdoc-0.14.1.tgz", - "integrity": "sha512-6Wci+Tp3CgPt/B9B0a3J4s3yMgLNSku6w5TV6mN+61C71UqsRBv2FUibBf3tPGlNxebgPHMEUzKpb1ggE8KCKw==", + "version": "0.14.2", + "resolved": "https://registry.npmjs.org/@microsoft/tsdoc/-/tsdoc-0.14.2.tgz", + "integrity": "sha512-9b8mPpKrfeGRuhFH5iO1iwCLeIIsV6+H1sRfxbkoGXIyQE2BTsPd9zqSqQJ+pv5sJ/hT5M1zvOFL02MnEezFug==", "dev": true }, "node_modules/@microsoft/tsdoc-config": { - "version": "0.16.1", - "resolved": "https://registry.npmjs.org/@microsoft/tsdoc-config/-/tsdoc-config-0.16.1.tgz", - "integrity": "sha512-2RqkwiD4uN6MLnHFljqBlZIXlt/SaUT6cuogU1w2ARw4nKuuppSmR0+s+NC+7kXBQykd9zzu0P4HtBpZT5zBpQ==", + "version": "0.16.2", + "resolved": "https://registry.npmjs.org/@microsoft/tsdoc-config/-/tsdoc-config-0.16.2.tgz", + "integrity": "sha512-OGiIzzoBLgWWR0UdRJX98oYO+XKGf7tiK4Zk6tQ/E4IJqGCe7dvkTvgDZV5cFJUzLGDOjeAXrnZoA6QkVySuxw==", "dev": true, "dependencies": { - "@microsoft/tsdoc": "0.14.1", + "@microsoft/tsdoc": "0.14.2", "ajv": "~6.12.6", "jju": "~1.4.0", "resolve": "~1.19.0" } }, - "node_modules/@microsoft/tsdoc-config/node_modules/resolve": { - "version": "1.19.0", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.19.0.tgz", - "integrity": "sha512-rArEXAgsBG4UgRGcynxWIWKFvh/XZCcS8UJdHhwy91zwAvCZIbcs+vAbflgBnNjYMs/i/i+/Ux6IZhML1yPvxg==", - "dev": true, - "dependencies": { - "is-core-module": "^2.1.0", - "path-parse": "^1.0.6" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, "node_modules/@nodelib/fs.scandir": { "version": "2.1.5", "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", @@ -1121,15 +1202,15 @@ } }, "node_modules/@protobuf-ts/plugin": { - "version": "2.7.0", - "resolved": "https://registry.npmjs.org/@protobuf-ts/plugin/-/plugin-2.7.0.tgz", - "integrity": "sha512-NpZBNsu7pe9CyjayY+jphHqjV4Ya3rP0Q1ban41pRiFPyFF0G+bpKdChOYxN1gCRz9XQWU9OyMt6fiaAsDpFPA==", + "version": "2.8.1", + "resolved": "https://registry.npmjs.org/@protobuf-ts/plugin/-/plugin-2.8.1.tgz", + "integrity": "sha512-lacRdXJ9TkTbI28U0KApsnVqnxeq1aZftOdq6LNPQJaIzBrVRxrMkqnnGWGQFYe0Tr93OKeW4A2lLjTkn32CuA==", "dev": true, "dependencies": { - "@protobuf-ts/plugin-framework": "^2.7.0", - "@protobuf-ts/protoc": "^2.7.0", - "@protobuf-ts/runtime": "^2.7.0", - "@protobuf-ts/runtime-rpc": "^2.7.0", + "@protobuf-ts/plugin-framework": "^2.8.1", + "@protobuf-ts/protoc": "^2.8.1", + "@protobuf-ts/runtime": "^2.8.1", + "@protobuf-ts/runtime-rpc": "^2.8.1", "typescript": "^3.9" }, "bin": { @@ -1138,12 +1219,12 @@ } }, "node_modules/@protobuf-ts/plugin-framework": { - "version": "2.7.0", - "resolved": "https://registry.npmjs.org/@protobuf-ts/plugin-framework/-/plugin-framework-2.7.0.tgz", - "integrity": "sha512-dnvgUVONeDRr0rv5Jyq4RXVLVZ/NdQ/Boh+FwUFddMesM2EqN/z2vwpNZhraym4Z1Oj27y0fqMMhzkh5e6eJrQ==", + "version": "2.8.1", + "resolved": "https://registry.npmjs.org/@protobuf-ts/plugin-framework/-/plugin-framework-2.8.1.tgz", + "integrity": "sha512-hfLoYIyxCI6Ro6LY1BltNBDcXWL+36SwnWR/hcF4ttPHLE3rMIpYbz4IwQsfeU2SKbBeGFhZv9rcnDJB22cXog==", "dev": true, "dependencies": { - "@protobuf-ts/runtime": "^2.7.0", + "@protobuf-ts/runtime": "^2.8.1", "typescript": "^3.9" } }, @@ -1174,38 +1255,38 @@ } }, "node_modules/@protobuf-ts/protoc": { - "version": "2.7.0", - "resolved": "https://registry.npmjs.org/@protobuf-ts/protoc/-/protoc-2.7.0.tgz", - "integrity": "sha512-YW61nbX9d3mWF44193S+bmWth5eFHxvrePQMUfdY8eEa3PTmhAUwgVCUBeCXEVUWgz1H/E0CnwdjlJgW4vQtOg==", + "version": "2.8.1", + "resolved": "https://registry.npmjs.org/@protobuf-ts/protoc/-/protoc-2.8.1.tgz", + "integrity": "sha512-6fehuL9bS22zCgPBBlESZjnoA4fxAUkOjMcaFMJSlVpN6CDN2O+c/Mo1pCXaNDO7FAidMPj5yhz48Kws4kOXEA==", "dev": true, "bin": { "protoc": "protoc.js" } }, "node_modules/@protobuf-ts/runtime": { - "version": "2.7.0", - "resolved": "https://registry.npmjs.org/@protobuf-ts/runtime/-/runtime-2.7.0.tgz", - "integrity": "sha512-CzunTplg81oMkF9MnSYiX2WOdHnAyHKnokZncgOHm5bt8iEfFNnUsMSbsWUus/ulRNIZ9VAVMjutd96vmySQaw==" + "version": "2.8.1", + "resolved": "https://registry.npmjs.org/@protobuf-ts/runtime/-/runtime-2.8.1.tgz", + "integrity": "sha512-D9M5hSumYCovIfNllt7N6ODh4q+LrjiMWtNETvooaf+a2XheZJ7kgjFlsFghti0CFWwtA//of4JXQfw9hU+cCw==" }, "node_modules/@protobuf-ts/runtime-rpc": { - "version": "2.7.0", - "resolved": "https://registry.npmjs.org/@protobuf-ts/runtime-rpc/-/runtime-rpc-2.7.0.tgz", - "integrity": "sha512-ha2HFJYLam1Zv04roq4MgYgdivoXv3s5uDQpr6jOAflAduNRWpB5IFegvPvtdc89j4xs7vuNPIGyZtP/MgYAXA==", + "version": "2.8.1", + "resolved": "https://registry.npmjs.org/@protobuf-ts/runtime-rpc/-/runtime-rpc-2.8.1.tgz", + "integrity": "sha512-hc+HJpoAu50by8aBS55UygcrzD8jAvRKWZMCRJ9XY3h9Gl2tciYysfzSH1SWtF6XOT/4b5CKnnmdMR3ad7uU5g==", "dev": true, "dependencies": { - "@protobuf-ts/runtime": "^2.7.0" + "@protobuf-ts/runtime": "^2.8.1" } }, "node_modules/@sinclair/typebox": { - "version": "0.24.20", - "resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.24.20.tgz", - "integrity": "sha512-kVaO5aEFZb33nPMTZBxiPEkY+slxiPtqC7QX8f9B3eGOMBvEfuMfxp9DSTTCsRJPumPKjrge4yagyssO4q6qzQ==", + "version": "0.24.51", + "resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.24.51.tgz", + "integrity": "sha512-1P1OROm/rdubP5aFDSZQILU0vrLCJ4fvHt6EoqHEM+2D/G5MK3bIaymUKLit8Js9gbns5UyJnkP/TZROLw4tUA==", "dev": true }, "node_modules/@sinonjs/commons": { - "version": "1.8.3", - "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-1.8.3.tgz", - "integrity": "sha512-xkNcLAn/wZaX14RPlwizcKicDk9G3F8m2nU3L7Ukm5zBgTwiT0wsoFAHx9Jq56fJA1z/7uKGtCRu16sOUCLIHQ==", + "version": "1.8.4", + "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-1.8.4.tgz", + "integrity": "sha512-RpmQdHVo8hCEHDVpO39zToS9jOhR6nw+/lQAzRNq9ErrGV9IeHM71XCn68svVl/euFeVW6BWX4p35gkhbOcSIQ==", "dev": true, "dependencies": { "type-detect": "4.0.8" @@ -1253,9 +1334,9 @@ } }, "node_modules/@types/babel__traverse": { - "version": "7.17.1", - "resolved": "https://registry.npmjs.org/@types/babel__traverse/-/babel__traverse-7.17.1.tgz", - "integrity": "sha512-kVzjari1s2YVi77D3w1yuvohV2idweYXMCDzqBiVNN63TcDWrIlTVOYpqVrvbbyOE/IyzBoTKF0fdnLPEORFxA==", + "version": "7.18.2", + "resolved": "https://registry.npmjs.org/@types/babel__traverse/-/babel__traverse-7.18.2.tgz", + "integrity": "sha512-FcFaxOr2V5KZCviw1TnutEMVUVsGt4D2hP1TAfXZAMKuHYW3xQhe3jTxNPWutgCJ3/X1c5yX8ZoGVEItxKbwBg==", "dev": true, "dependencies": { "@babel/types": "^7.3.0" @@ -1295,9 +1376,9 @@ } }, "node_modules/@types/jest": { - "version": "28.1.7", - "resolved": "https://registry.npmjs.org/@types/jest/-/jest-28.1.7.tgz", - "integrity": "sha512-acDN4VHD40V24tgu0iC44jchXavRNVFXQ/E6Z5XNsswgoSO/4NgsXoEYmPUGookKldlZQyIpmrEXsHI9cA3ZTA==", + "version": "28.1.8", + "resolved": "https://registry.npmjs.org/@types/jest/-/jest-28.1.8.tgz", + "integrity": "sha512-8TJkV++s7B6XqnDrzR1m/TT0A0h948Pnl/097veySPN67VRAgQ4gZ7n2KfJo2rVq6njQjdxU3GCCyDvAeuHoiw==", "dev": true, "dependencies": { "expect": "^28.0.0", @@ -1317,9 +1398,15 @@ "dev": true }, "node_modules/@types/prettier": { - "version": "2.6.3", - "resolved": "https://registry.npmjs.org/@types/prettier/-/prettier-2.6.3.tgz", - "integrity": "sha512-ymZk3LEC/fsut+/Q5qejp6R9O1rMxz3XaRHDV6kX8MrGAhOSPqVARbDi+EZvInBpw+BnCX3TD240byVkOfQsHg==", + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/@types/prettier/-/prettier-2.7.1.tgz", + "integrity": "sha512-ri0UmynRRvZiiUJdiz38MmIblKK+oH30MztdBVR95dv/Ubw6neWSb8u1XpRb72L4qsZOhz+L+z9JD40SJmfWow==", + "dev": true + }, + "node_modules/@types/semver": { + "version": "7.3.13", + "resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.3.13.tgz", + "integrity": "sha512-21cFJr9z3g5dW8B0CVI9g2O9beqaThGQ6ZFBqHfwhzLDKUxaqTIy3vnfah/UPkfOiF2pLq+tGz+W8RyCskuslw==", "dev": true }, "node_modules/@types/stack-utils": { @@ -1329,9 +1416,9 @@ "dev": true }, "node_modules/@types/yargs": { - "version": "17.0.10", - "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.10.tgz", - "integrity": "sha512-gmEaFwpj/7f/ROdtIlci1R1VYU1J4j95m8T+Tj3iBgiBFKg1foE/PSl93bBd5T9LDXNPo8UlNN6W0qwD8O5OaA==", + "version": "17.0.13", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.13.tgz", + "integrity": "sha512-9sWaruZk2JGxIQU+IhI1fhPYRcQ0UuTNuKuCW9bR5fp7qi2Llf7WDzNa17Cy7TKnh3cdxDOiyTu6gaLS0eDatg==", "dev": true, "dependencies": { "@types/yargs-parser": "*" @@ -1344,17 +1431,17 @@ "dev": true }, "node_modules/@typescript-eslint/eslint-plugin": { - "version": "5.30.6", - "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.30.6.tgz", - "integrity": "sha512-J4zYMIhgrx4MgnZrSDD7sEnQp7FmhKNOaqaOpaoQ/SfdMfRB/0yvK74hTnvH+VQxndZynqs5/Hn4t+2/j9bADg==", + "version": "5.42.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.42.0.tgz", + "integrity": "sha512-5TJh2AgL6+wpL8H/GTSjNb4WrjKoR2rqvFxR/DDTqYNk6uXn8BJMEcncLSpMbf/XV1aS0jAjYwn98uvVCiAywQ==", "dev": true, "dependencies": { - "@typescript-eslint/scope-manager": "5.30.6", - "@typescript-eslint/type-utils": "5.30.6", - "@typescript-eslint/utils": "5.30.6", + "@typescript-eslint/scope-manager": "5.42.0", + "@typescript-eslint/type-utils": "5.42.0", + "@typescript-eslint/utils": "5.42.0", "debug": "^4.3.4", - "functional-red-black-tree": "^1.0.1", "ignore": "^5.2.0", + "natural-compare-lite": "^1.4.0", "regexpp": "^3.2.0", "semver": "^7.3.7", "tsutils": "^3.21.0" @@ -1377,14 +1464,14 @@ } }, "node_modules/@typescript-eslint/parser": { - "version": "5.30.6", - "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-5.30.6.tgz", - "integrity": "sha512-gfF9lZjT0p2ZSdxO70Xbw8w9sPPJGfAdjK7WikEjB3fcUI/yr9maUVEdqigBjKincUYNKOmf7QBMiTf719kbrA==", + "version": "5.42.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-5.42.0.tgz", + "integrity": "sha512-Ixh9qrOTDRctFg3yIwrLkgf33AHyEIn6lhyf5cCfwwiGtkWhNpVKlEZApi3inGQR/barWnY7qY8FbGKBO7p3JA==", "dev": true, "dependencies": { - "@typescript-eslint/scope-manager": "5.30.6", - "@typescript-eslint/types": "5.30.6", - "@typescript-eslint/typescript-estree": "5.30.6", + "@typescript-eslint/scope-manager": "5.42.0", + "@typescript-eslint/types": "5.42.0", + "@typescript-eslint/typescript-estree": "5.42.0", "debug": "^4.3.4" }, "engines": { @@ -1404,13 +1491,13 @@ } }, "node_modules/@typescript-eslint/scope-manager": { - "version": "5.30.6", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.30.6.tgz", - "integrity": "sha512-Hkq5PhLgtVoW1obkqYH0i4iELctEKixkhWLPTYs55doGUKCASvkjOXOd/pisVeLdO24ZX9D6yymJ/twqpJiG3g==", + "version": "5.42.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.42.0.tgz", + "integrity": "sha512-l5/3IBHLH0Bv04y+H+zlcLiEMEMjWGaCX6WyHE5Uk2YkSGAMlgdUPsT/ywTSKgu9D1dmmKMYgYZijObfA39Wow==", "dev": true, "dependencies": { - "@typescript-eslint/types": "5.30.6", - "@typescript-eslint/visitor-keys": "5.30.6" + "@typescript-eslint/types": "5.42.0", + "@typescript-eslint/visitor-keys": "5.42.0" }, "engines": { "node": "^12.22.0 || ^14.17.0 || >=16.0.0" @@ -1421,12 +1508,13 @@ } }, "node_modules/@typescript-eslint/type-utils": { - "version": "5.30.6", - "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-5.30.6.tgz", - "integrity": "sha512-GFVVzs2j0QPpM+NTDMXtNmJKlF842lkZKDSanIxf+ArJsGeZUIaeT4jGg+gAgHt7AcQSFwW7htzF/rbAh2jaVA==", + "version": "5.42.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-5.42.0.tgz", + "integrity": "sha512-HW14TXC45dFVZxnVW8rnUGnvYyRC0E/vxXShFCthcC9VhVTmjqOmtqj6H5rm9Zxv+ORxKA/1aLGD7vmlLsdlOg==", "dev": true, "dependencies": { - "@typescript-eslint/utils": "5.30.6", + "@typescript-eslint/typescript-estree": "5.42.0", + "@typescript-eslint/utils": "5.42.0", "debug": "^4.3.4", "tsutils": "^3.21.0" }, @@ -1447,9 +1535,9 @@ } }, "node_modules/@typescript-eslint/types": { - "version": "5.30.6", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.30.6.tgz", - "integrity": "sha512-HdnP8HioL1F7CwVmT4RaaMX57RrfqsOMclZc08wGMiDYJBsLGBM7JwXM4cZJmbWLzIR/pXg1kkrBBVpxTOwfUg==", + "version": "5.42.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.42.0.tgz", + "integrity": "sha512-t4lzO9ZOAUcHY6bXQYRuu+3SSYdD9TS8ooApZft4WARt4/f2Cj/YpvbTe8A4GuhT4bNW72goDMOy7SW71mZwGw==", "dev": true, "engines": { "node": "^12.22.0 || ^14.17.0 || >=16.0.0" @@ -1460,13 +1548,13 @@ } }, "node_modules/@typescript-eslint/typescript-estree": { - "version": "5.30.6", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.30.6.tgz", - "integrity": "sha512-Z7TgPoeYUm06smfEfYF0RBkpF8csMyVnqQbLYiGgmUSTaSXTP57bt8f0UFXstbGxKIreTwQCujtaH0LY9w9B+A==", + "version": "5.42.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.42.0.tgz", + "integrity": "sha512-2O3vSq794x3kZGtV7i4SCWZWCwjEtkWfVqX4m5fbUBomOsEOyd6OAD1qU2lbvV5S8tgy/luJnOYluNyYVeOTTg==", "dev": true, "dependencies": { - "@typescript-eslint/types": "5.30.6", - "@typescript-eslint/visitor-keys": "5.30.6", + "@typescript-eslint/types": "5.42.0", + "@typescript-eslint/visitor-keys": "5.42.0", "debug": "^4.3.4", "globby": "^11.1.0", "is-glob": "^4.0.3", @@ -1487,17 +1575,19 @@ } }, "node_modules/@typescript-eslint/utils": { - "version": "5.30.6", - "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-5.30.6.tgz", - "integrity": "sha512-xFBLc/esUbLOJLk9jKv0E9gD/OH966M40aY9jJ8GiqpSkP2xOV908cokJqqhVd85WoIvHVHYXxSFE4cCSDzVvA==", + "version": "5.42.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-5.42.0.tgz", + "integrity": "sha512-JZ++3+h1vbeG1NUECXQZE3hg0kias9kOtcQr3+JVQ3whnjvKuMyktJAAIj6743OeNPnGBmjj7KEmiDL7qsdnCQ==", "dev": true, "dependencies": { "@types/json-schema": "^7.0.9", - "@typescript-eslint/scope-manager": "5.30.6", - "@typescript-eslint/types": "5.30.6", - "@typescript-eslint/typescript-estree": "5.30.6", + "@types/semver": "^7.3.12", + "@typescript-eslint/scope-manager": "5.42.0", + "@typescript-eslint/types": "5.42.0", + "@typescript-eslint/typescript-estree": "5.42.0", "eslint-scope": "^5.1.1", - "eslint-utils": "^3.0.0" + "eslint-utils": "^3.0.0", + "semver": "^7.3.7" }, "engines": { "node": "^12.22.0 || ^14.17.0 || >=16.0.0" @@ -1510,35 +1600,13 @@ "eslint": "^6.0.0 || ^7.0.0 || ^8.0.0" } }, - "node_modules/@typescript-eslint/utils/node_modules/eslint-scope": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz", - "integrity": "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==", - "dev": true, - "dependencies": { - "esrecurse": "^4.3.0", - "estraverse": "^4.1.1" - }, - "engines": { - "node": ">=8.0.0" - } - }, - "node_modules/@typescript-eslint/utils/node_modules/estraverse": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", - "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", - "dev": true, - "engines": { - "node": ">=4.0" - } - }, "node_modules/@typescript-eslint/visitor-keys": { - "version": "5.30.6", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.30.6.tgz", - "integrity": "sha512-41OiCjdL2mCaSDi2SvYbzFLlqqlm5v1ZW9Ym55wXKL/Rx6OOB1IbuFGo71Fj6Xy90gJDFTlgOS+vbmtGHPTQQA==", + "version": "5.42.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.42.0.tgz", + "integrity": "sha512-QHbu5Hf/2lOEOwy+IUw0GoSCuAzByTAWWrOTKzTzsotiUnWFpuKnXcAhC9YztAf2EElQ0VvIK+pHJUPkM0q7jg==", "dev": true, "dependencies": { - "@typescript-eslint/types": "5.30.6", + "@typescript-eslint/types": "5.42.0", "eslint-visitor-keys": "^3.3.0" }, "engines": { @@ -1550,9 +1618,9 @@ } }, "node_modules/acorn": { - "version": "8.8.0", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.8.0.tgz", - "integrity": "sha512-QOxyigPVrpZ2GXT+PFyZTl6TtOFc5egxHIP9IlQ+RbupQuX4RkT/Bee4/kQuC02Xkzg84JcT7oLYtDIQxp+v7w==", + "version": "8.8.1", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.8.1.tgz", + "integrity": "sha512-7zFpHzhnqYKrkYdUjF1HI1bzd0VygEGX8lFk4k5zVMqHEoES+P+7TKI+EvLO9WVMJ8eekdO0aDEK044xTXwPPA==", "bin": { "acorn": "bin/acorn" }, @@ -1789,9 +1857,9 @@ } }, "node_modules/browserslist": { - "version": "4.21.2", - "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.21.2.tgz", - "integrity": "sha512-MonuOgAtUB46uP5CezYbRaYKBNt2LxP0yX+Pmj4LkcDFGkn9Cbpi83d9sCjwQDErXsIJSzY5oKGDbgOlF/LPAA==", + "version": "4.21.4", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.21.4.tgz", + "integrity": "sha512-CBHJJdDmgjl3daYjN5Cp5kbTf1mUhZoS+beLklHIvkOWscs83YAhLlF3Wsh/lciQYAcbBJgTOD44VtG31ZM4Hw==", "dev": true, "funding": [ { @@ -1804,10 +1872,10 @@ } ], "dependencies": { - "caniuse-lite": "^1.0.30001366", - "electron-to-chromium": "^1.4.188", + "caniuse-lite": "^1.0.30001400", + "electron-to-chromium": "^1.4.251", "node-releases": "^2.0.6", - "update-browserslist-db": "^1.0.4" + "update-browserslist-db": "^1.0.9" }, "bin": { "browserslist": "cli.js" @@ -1843,6 +1911,17 @@ "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==", "dev": true }, + "node_modules/busboy": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/busboy/-/busboy-1.6.0.tgz", + "integrity": "sha512-8SFQbg/0hQ9xy3UNTB0YEnsNBbWfhf7RtnzpL7TkBiTBRfrQ9Fxcnz7VJsleJpyp6rVLvXiuORqjlHi5q+PYuA==", + "dependencies": { + "streamsearch": "^1.1.0" + }, + "engines": { + "node": ">=10.16.0" + } + }, "node_modules/callsites": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", @@ -1862,9 +1941,9 @@ } }, "node_modules/caniuse-lite": { - "version": "1.0.30001367", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001367.tgz", - "integrity": "sha512-XDgbeOHfifWV3GEES2B8rtsrADx4Jf+juKX2SICJcaUhjYBO3bR96kvEIHa15VU6ohtOhBZuPGGYGbXMRn0NCw==", + "version": "1.0.30001430", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001430.tgz", + "integrity": "sha512-IB1BXTZKPDVPM7cnV4iaKaHxckvdr/3xtctB3f7Hmenx3qYBhGtTZ//7EllK66aKXW98Lx0+7Yr0kxBtIt3tzg==", "dev": true, "funding": [ { @@ -1903,9 +1982,9 @@ } }, "node_modules/ci-info": { - "version": "3.3.2", - "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-3.3.2.tgz", - "integrity": "sha512-xmDt/QIAdeZ9+nfdPsaBCpMvHNLFiLdjj59qjqn+6iPe6YmHGQ35sBnQ8uslRBXFmXkiZQOJRjvQeoGppoTjjg==", + "version": "3.5.0", + "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-3.5.0.tgz", + "integrity": "sha512-yH4RezKOGlOhxkmhbeNuC4eYZKAUsEaGtBuBzDDP1eFUKiccDWzBABxBfOx31IDwDIXMTxWuwAxUGModvkbuVw==", "dev": true }, "node_modules/cjs-module-lexer": { @@ -1915,14 +1994,17 @@ "dev": true }, "node_modules/cliui": { - "version": "7.0.4", - "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz", - "integrity": "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==", + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz", + "integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==", "dev": true, "dependencies": { "string-width": "^4.2.0", - "strip-ansi": "^6.0.0", + "strip-ansi": "^6.0.1", "wrap-ansi": "^7.0.0" + }, + "engines": { + "node": ">=12" } }, "node_modules/co": { @@ -1966,13 +2048,10 @@ "dev": true }, "node_modules/convert-source-map": { - "version": "1.8.0", - "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.8.0.tgz", - "integrity": "sha512-+OQdjP49zViI/6i7nIJpA8rAl4sV/JdPfU9nZs3VqOwGIgizICvuN2ru6fMd+4llL0tar18UYJXfZ/TWtmhUjA==", - "dev": true, - "dependencies": { - "safe-buffer": "~5.1.1" - } + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.9.0.tgz", + "integrity": "sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A==", + "dev": true }, "node_modules/cross-spawn": { "version": "7.0.3", @@ -2151,9 +2230,9 @@ } }, "node_modules/electron-to-chromium": { - "version": "1.4.192", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.192.tgz", - "integrity": "sha512-8nCXyIQY9An88NXAp+PuPy5h3/w5ZY7Iu2lag65Q0XREprcat5F8gKhoHsBUnQcFuCRnmevpR8yEBYRU3d2HDw==", + "version": "1.4.284", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.284.tgz", + "integrity": "sha512-M8WEXFuKXMYMVr45fo8mq0wUrrJHheiKZf6BArTKk9ZBYCKJEOU5H8cdWgDT+qCVZf7Na4lVUaZsA+h6uA9+PA==", "dev": true }, "node_modules/emittery": { @@ -2175,9 +2254,9 @@ "dev": true }, "node_modules/entities": { - "version": "4.3.1", - "resolved": "https://registry.npmjs.org/entities/-/entities-4.3.1.tgz", - "integrity": "sha512-o4q/dYJlmyjP2zfnaWDUC6A3BQFmVTX+tZPezK7k0GLSU9QYCauscf5Y+qcEPzKL+EixVouYDgLQK5H9GrLpkg==", + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/entities/-/entities-4.4.0.tgz", + "integrity": "sha512-oYp7156SP8LkeGD0GF85ad1X9Ai79WtRsZ2gxJqtBuzH+98YUV6jkHEKlZkMbcrjJjIVJNIDP/3WL9wQkoPbWA==", "engines": { "node": ">=0.12" }, @@ -2195,9 +2274,9 @@ } }, "node_modules/esbuild": { - "version": "0.14.49", - "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.14.49.tgz", - "integrity": "sha512-/TlVHhOaq7Yz8N1OJrjqM3Auzo5wjvHFLk+T8pIue+fhnhIMpfAzsG6PLVMbFveVxqD2WOp3QHei+52IMUNmCw==", + "version": "0.14.54", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.14.54.tgz", + "integrity": "sha512-Cy9llcy8DvET5uznocPyqL3BFRrFXSVqbgpMJ9Wz8oVjZlh/zUSNbPRbov0VX7VxN2JH1Oa0uNxZ7eLRb62pJA==", "dev": true, "hasInstallScript": true, "bin": { @@ -2207,32 +2286,33 @@ "node": ">=12" }, "optionalDependencies": { - "esbuild-android-64": "0.14.49", - "esbuild-android-arm64": "0.14.49", - "esbuild-darwin-64": "0.14.49", - "esbuild-darwin-arm64": "0.14.49", - "esbuild-freebsd-64": "0.14.49", - "esbuild-freebsd-arm64": "0.14.49", - "esbuild-linux-32": "0.14.49", - "esbuild-linux-64": "0.14.49", - "esbuild-linux-arm": "0.14.49", - "esbuild-linux-arm64": "0.14.49", - "esbuild-linux-mips64le": "0.14.49", - "esbuild-linux-ppc64le": "0.14.49", - "esbuild-linux-riscv64": "0.14.49", - "esbuild-linux-s390x": "0.14.49", - "esbuild-netbsd-64": "0.14.49", - "esbuild-openbsd-64": "0.14.49", - "esbuild-sunos-64": "0.14.49", - "esbuild-windows-32": "0.14.49", - "esbuild-windows-64": "0.14.49", - "esbuild-windows-arm64": "0.14.49" + "@esbuild/linux-loong64": "0.14.54", + "esbuild-android-64": "0.14.54", + "esbuild-android-arm64": "0.14.54", + "esbuild-darwin-64": "0.14.54", + "esbuild-darwin-arm64": "0.14.54", + "esbuild-freebsd-64": "0.14.54", + "esbuild-freebsd-arm64": "0.14.54", + "esbuild-linux-32": "0.14.54", + "esbuild-linux-64": "0.14.54", + "esbuild-linux-arm": "0.14.54", + "esbuild-linux-arm64": "0.14.54", + "esbuild-linux-mips64le": "0.14.54", + "esbuild-linux-ppc64le": "0.14.54", + "esbuild-linux-riscv64": "0.14.54", + "esbuild-linux-s390x": "0.14.54", + "esbuild-netbsd-64": "0.14.54", + "esbuild-openbsd-64": "0.14.54", + "esbuild-sunos-64": "0.14.54", + "esbuild-windows-32": "0.14.54", + "esbuild-windows-64": "0.14.54", + "esbuild-windows-arm64": "0.14.54" } }, "node_modules/esbuild-android-64": { - "version": "0.14.49", - "resolved": "https://registry.npmjs.org/esbuild-android-64/-/esbuild-android-64-0.14.49.tgz", - "integrity": "sha512-vYsdOTD+yi+kquhBiFWl3tyxnj2qZJsl4tAqwhT90ktUdnyTizgle7TjNx6Ar1bN7wcwWqZ9QInfdk2WVagSww==", + "version": "0.14.54", + "resolved": "https://registry.npmjs.org/esbuild-android-64/-/esbuild-android-64-0.14.54.tgz", + "integrity": "sha512-Tz2++Aqqz0rJ7kYBfz+iqyE3QMycD4vk7LBRyWaAVFgFtQ/O8EJOnVmTOiDWYZ/uYzB4kvP+bqejYdVKzE5lAQ==", "cpu": [ "x64" ], @@ -2246,9 +2326,9 @@ } }, "node_modules/esbuild-android-arm64": { - "version": "0.14.49", - "resolved": "https://registry.npmjs.org/esbuild-android-arm64/-/esbuild-android-arm64-0.14.49.tgz", - "integrity": "sha512-g2HGr/hjOXCgSsvQZ1nK4nW/ei8JUx04Li74qub9qWrStlysaVmadRyTVuW32FGIpLQyc5sUjjZopj49eGGM2g==", + "version": "0.14.54", + "resolved": "https://registry.npmjs.org/esbuild-android-arm64/-/esbuild-android-arm64-0.14.54.tgz", + "integrity": "sha512-F9E+/QDi9sSkLaClO8SOV6etqPd+5DgJje1F9lOWoNncDdOBL2YF59IhsWATSt0TLZbYCf3pNlTHvVV5VfHdvg==", "cpu": [ "arm64" ], @@ -2262,9 +2342,9 @@ } }, "node_modules/esbuild-darwin-64": { - "version": "0.14.49", - "resolved": "https://registry.npmjs.org/esbuild-darwin-64/-/esbuild-darwin-64-0.14.49.tgz", - "integrity": "sha512-3rvqnBCtX9ywso5fCHixt2GBCUsogNp9DjGmvbBohh31Ces34BVzFltMSxJpacNki96+WIcX5s/vum+ckXiLYg==", + "version": "0.14.54", + "resolved": "https://registry.npmjs.org/esbuild-darwin-64/-/esbuild-darwin-64-0.14.54.tgz", + "integrity": "sha512-jtdKWV3nBviOd5v4hOpkVmpxsBy90CGzebpbO9beiqUYVMBtSc0AL9zGftFuBon7PNDcdvNCEuQqw2x0wP9yug==", "cpu": [ "x64" ], @@ -2278,9 +2358,9 @@ } }, "node_modules/esbuild-darwin-arm64": { - "version": "0.14.49", - "resolved": "https://registry.npmjs.org/esbuild-darwin-arm64/-/esbuild-darwin-arm64-0.14.49.tgz", - "integrity": "sha512-XMaqDxO846srnGlUSJnwbijV29MTKUATmOLyQSfswbK/2X5Uv28M9tTLUJcKKxzoo9lnkYPsx2o8EJcTYwCs/A==", + "version": "0.14.54", + "resolved": "https://registry.npmjs.org/esbuild-darwin-arm64/-/esbuild-darwin-arm64-0.14.54.tgz", + "integrity": "sha512-OPafJHD2oUPyvJMrsCvDGkRrVCar5aVyHfWGQzY1dWnzErjrDuSETxwA2HSsyg2jORLY8yBfzc1MIpUkXlctmw==", "cpu": [ "arm64" ], @@ -2294,9 +2374,9 @@ } }, "node_modules/esbuild-freebsd-64": { - "version": "0.14.49", - "resolved": "https://registry.npmjs.org/esbuild-freebsd-64/-/esbuild-freebsd-64-0.14.49.tgz", - "integrity": "sha512-NJ5Q6AjV879mOHFri+5lZLTp5XsO2hQ+KSJYLbfY9DgCu8s6/Zl2prWXVANYTeCDLlrIlNNYw8y34xqyLDKOmQ==", + "version": "0.14.54", + "resolved": "https://registry.npmjs.org/esbuild-freebsd-64/-/esbuild-freebsd-64-0.14.54.tgz", + "integrity": "sha512-OKwd4gmwHqOTp4mOGZKe/XUlbDJ4Q9TjX0hMPIDBUWWu/kwhBAudJdBoxnjNf9ocIB6GN6CPowYpR/hRCbSYAg==", "cpu": [ "x64" ], @@ -2310,9 +2390,9 @@ } }, "node_modules/esbuild-freebsd-arm64": { - "version": "0.14.49", - "resolved": "https://registry.npmjs.org/esbuild-freebsd-arm64/-/esbuild-freebsd-arm64-0.14.49.tgz", - "integrity": "sha512-lFLtgXnAc3eXYqj5koPlBZvEbBSOSUbWO3gyY/0+4lBdRqELyz4bAuamHvmvHW5swJYL7kngzIZw6kdu25KGOA==", + "version": "0.14.54", + "resolved": "https://registry.npmjs.org/esbuild-freebsd-arm64/-/esbuild-freebsd-arm64-0.14.54.tgz", + "integrity": "sha512-sFwueGr7OvIFiQT6WeG0jRLjkjdqWWSrfbVwZp8iMP+8UHEHRBvlaxL6IuKNDwAozNUmbb8nIMXa7oAOARGs1Q==", "cpu": [ "arm64" ], @@ -2326,9 +2406,9 @@ } }, "node_modules/esbuild-linux-32": { - "version": "0.14.49", - "resolved": "https://registry.npmjs.org/esbuild-linux-32/-/esbuild-linux-32-0.14.49.tgz", - "integrity": "sha512-zTTH4gr2Kb8u4QcOpTDVn7Z8q7QEIvFl/+vHrI3cF6XOJS7iEI1FWslTo3uofB2+mn6sIJEQD9PrNZKoAAMDiA==", + "version": "0.14.54", + "resolved": "https://registry.npmjs.org/esbuild-linux-32/-/esbuild-linux-32-0.14.54.tgz", + "integrity": "sha512-1ZuY+JDI//WmklKlBgJnglpUL1owm2OX+8E1syCD6UAxcMM/XoWd76OHSjl/0MR0LisSAXDqgjT3uJqT67O3qw==", "cpu": [ "ia32" ], @@ -2342,9 +2422,9 @@ } }, "node_modules/esbuild-linux-64": { - "version": "0.14.49", - "resolved": "https://registry.npmjs.org/esbuild-linux-64/-/esbuild-linux-64-0.14.49.tgz", - "integrity": "sha512-hYmzRIDzFfLrB5c1SknkxzM8LdEUOusp6M2TnuQZJLRtxTgyPnZZVtyMeCLki0wKgYPXkFsAVhi8vzo2mBNeTg==", + "version": "0.14.54", + "resolved": "https://registry.npmjs.org/esbuild-linux-64/-/esbuild-linux-64-0.14.54.tgz", + "integrity": "sha512-EgjAgH5HwTbtNsTqQOXWApBaPVdDn7XcK+/PtJwZLT1UmpLoznPd8c5CxqsH2dQK3j05YsB3L17T8vE7cp4cCg==", "cpu": [ "x64" ], @@ -2358,9 +2438,9 @@ } }, "node_modules/esbuild-linux-arm": { - "version": "0.14.49", - "resolved": "https://registry.npmjs.org/esbuild-linux-arm/-/esbuild-linux-arm-0.14.49.tgz", - "integrity": "sha512-iE3e+ZVv1Qz1Sy0gifIsarJMQ89Rpm9mtLSRtG3AH0FPgAzQ5Z5oU6vYzhc/3gSPi2UxdCOfRhw2onXuFw/0lg==", + "version": "0.14.54", + "resolved": "https://registry.npmjs.org/esbuild-linux-arm/-/esbuild-linux-arm-0.14.54.tgz", + "integrity": "sha512-qqz/SjemQhVMTnvcLGoLOdFpCYbz4v4fUo+TfsWG+1aOu70/80RV6bgNpR2JCrppV2moUQkww+6bWxXRL9YMGw==", "cpu": [ "arm" ], @@ -2374,9 +2454,9 @@ } }, "node_modules/esbuild-linux-arm64": { - "version": "0.14.49", - "resolved": "https://registry.npmjs.org/esbuild-linux-arm64/-/esbuild-linux-arm64-0.14.49.tgz", - "integrity": "sha512-KLQ+WpeuY+7bxukxLz5VgkAAVQxUv67Ft4DmHIPIW+2w3ObBPQhqNoeQUHxopoW/aiOn3m99NSmSV+bs4BSsdA==", + "version": "0.14.54", + "resolved": "https://registry.npmjs.org/esbuild-linux-arm64/-/esbuild-linux-arm64-0.14.54.tgz", + "integrity": "sha512-WL71L+0Rwv+Gv/HTmxTEmpv0UgmxYa5ftZILVi2QmZBgX3q7+tDeOQNqGtdXSdsL8TQi1vIaVFHUPDe0O0kdig==", "cpu": [ "arm64" ], @@ -2390,9 +2470,9 @@ } }, "node_modules/esbuild-linux-mips64le": { - "version": "0.14.49", - "resolved": "https://registry.npmjs.org/esbuild-linux-mips64le/-/esbuild-linux-mips64le-0.14.49.tgz", - "integrity": "sha512-n+rGODfm8RSum5pFIqFQVQpYBw+AztL8s6o9kfx7tjfK0yIGF6tm5HlG6aRjodiiKkH2xAiIM+U4xtQVZYU4rA==", + "version": "0.14.54", + "resolved": "https://registry.npmjs.org/esbuild-linux-mips64le/-/esbuild-linux-mips64le-0.14.54.tgz", + "integrity": "sha512-qTHGQB8D1etd0u1+sB6p0ikLKRVuCWhYQhAHRPkO+OF3I/iSlTKNNS0Lh2Oc0g0UFGguaFZZiPJdJey3AGpAlw==", "cpu": [ "mips64el" ], @@ -2406,9 +2486,9 @@ } }, "node_modules/esbuild-linux-ppc64le": { - "version": "0.14.49", - "resolved": "https://registry.npmjs.org/esbuild-linux-ppc64le/-/esbuild-linux-ppc64le-0.14.49.tgz", - "integrity": "sha512-WP9zR4HX6iCBmMFH+XHHng2LmdoIeUmBpL4aL2TR8ruzXyT4dWrJ5BSbT8iNo6THN8lod6GOmYDLq/dgZLalGw==", + "version": "0.14.54", + "resolved": "https://registry.npmjs.org/esbuild-linux-ppc64le/-/esbuild-linux-ppc64le-0.14.54.tgz", + "integrity": "sha512-j3OMlzHiqwZBDPRCDFKcx595XVfOfOnv68Ax3U4UKZ3MTYQB5Yz3X1mn5GnodEVYzhtZgxEBidLWeIs8FDSfrQ==", "cpu": [ "ppc64" ], @@ -2422,9 +2502,9 @@ } }, "node_modules/esbuild-linux-riscv64": { - "version": "0.14.49", - "resolved": "https://registry.npmjs.org/esbuild-linux-riscv64/-/esbuild-linux-riscv64-0.14.49.tgz", - "integrity": "sha512-h66ORBz+Dg+1KgLvzTVQEA1LX4XBd1SK0Fgbhhw4akpG/YkN8pS6OzYI/7SGENiN6ao5hETRDSkVcvU9NRtkMQ==", + "version": "0.14.54", + "resolved": "https://registry.npmjs.org/esbuild-linux-riscv64/-/esbuild-linux-riscv64-0.14.54.tgz", + "integrity": "sha512-y7Vt7Wl9dkOGZjxQZnDAqqn+XOqFD7IMWiewY5SPlNlzMX39ocPQlOaoxvT4FllA5viyV26/QzHtvTjVNOxHZg==", "cpu": [ "riscv64" ], @@ -2438,9 +2518,9 @@ } }, "node_modules/esbuild-linux-s390x": { - "version": "0.14.49", - "resolved": "https://registry.npmjs.org/esbuild-linux-s390x/-/esbuild-linux-s390x-0.14.49.tgz", - "integrity": "sha512-DhrUoFVWD+XmKO1y7e4kNCqQHPs6twz6VV6Uezl/XHYGzM60rBewBF5jlZjG0nCk5W/Xy6y1xWeopkrhFFM0sQ==", + "version": "0.14.54", + "resolved": "https://registry.npmjs.org/esbuild-linux-s390x/-/esbuild-linux-s390x-0.14.54.tgz", + "integrity": "sha512-zaHpW9dziAsi7lRcyV4r8dhfG1qBidQWUXweUjnw+lliChJqQr+6XD71K41oEIC3Mx1KStovEmlzm+MkGZHnHA==", "cpu": [ "s390x" ], @@ -2454,9 +2534,9 @@ } }, "node_modules/esbuild-netbsd-64": { - "version": "0.14.49", - "resolved": "https://registry.npmjs.org/esbuild-netbsd-64/-/esbuild-netbsd-64-0.14.49.tgz", - "integrity": "sha512-BXaUwFOfCy2T+hABtiPUIpWjAeWK9P8O41gR4Pg73hpzoygVGnj0nI3YK4SJhe52ELgtdgWP/ckIkbn2XaTxjQ==", + "version": "0.14.54", + "resolved": "https://registry.npmjs.org/esbuild-netbsd-64/-/esbuild-netbsd-64-0.14.54.tgz", + "integrity": "sha512-PR01lmIMnfJTgeU9VJTDY9ZerDWVFIUzAtJuDHwwceppW7cQWjBBqP48NdeRtoP04/AtO9a7w3viI+PIDr6d+w==", "cpu": [ "x64" ], @@ -2470,9 +2550,9 @@ } }, "node_modules/esbuild-openbsd-64": { - "version": "0.14.49", - "resolved": "https://registry.npmjs.org/esbuild-openbsd-64/-/esbuild-openbsd-64-0.14.49.tgz", - "integrity": "sha512-lP06UQeLDGmVPw9Rg437Btu6J9/BmyhdoefnQ4gDEJTtJvKtQaUcOQrhjTq455ouZN4EHFH1h28WOJVANK41kA==", + "version": "0.14.54", + "resolved": "https://registry.npmjs.org/esbuild-openbsd-64/-/esbuild-openbsd-64-0.14.54.tgz", + "integrity": "sha512-Qyk7ikT2o7Wu76UsvvDS5q0amJvmRzDyVlL0qf5VLsLchjCa1+IAvd8kTBgUxD7VBUUVgItLkk609ZHUc1oCaw==", "cpu": [ "x64" ], @@ -2486,9 +2566,9 @@ } }, "node_modules/esbuild-sunos-64": { - "version": "0.14.49", - "resolved": "https://registry.npmjs.org/esbuild-sunos-64/-/esbuild-sunos-64-0.14.49.tgz", - "integrity": "sha512-4c8Zowp+V3zIWje329BeLbGh6XI9c/rqARNaj5yPHdC61pHI9UNdDxT3rePPJeWcEZVKjkiAS6AP6kiITp7FSw==", + "version": "0.14.54", + "resolved": "https://registry.npmjs.org/esbuild-sunos-64/-/esbuild-sunos-64-0.14.54.tgz", + "integrity": "sha512-28GZ24KmMSeKi5ueWzMcco6EBHStL3B6ubM7M51RmPwXQGLe0teBGJocmWhgwccA1GeFXqxzILIxXpHbl9Q/Kw==", "cpu": [ "x64" ], @@ -2502,9 +2582,9 @@ } }, "node_modules/esbuild-windows-32": { - "version": "0.14.49", - "resolved": "https://registry.npmjs.org/esbuild-windows-32/-/esbuild-windows-32-0.14.49.tgz", - "integrity": "sha512-q7Rb+J9yHTeKr9QTPDYkqfkEj8/kcKz9lOabDuvEXpXuIcosWCJgo5Z7h/L4r7rbtTH4a8U2FGKb6s1eeOHmJA==", + "version": "0.14.54", + "resolved": "https://registry.npmjs.org/esbuild-windows-32/-/esbuild-windows-32-0.14.54.tgz", + "integrity": "sha512-T+rdZW19ql9MjS7pixmZYVObd9G7kcaZo+sETqNH4RCkuuYSuv9AGHUVnPoP9hhuE1WM1ZimHz1CIBHBboLU7w==", "cpu": [ "ia32" ], @@ -2518,9 +2598,9 @@ } }, "node_modules/esbuild-windows-64": { - "version": "0.14.49", - "resolved": "https://registry.npmjs.org/esbuild-windows-64/-/esbuild-windows-64-0.14.49.tgz", - "integrity": "sha512-+Cme7Ongv0UIUTniPqfTX6mJ8Deo7VXw9xN0yJEN1lQMHDppTNmKwAM3oGbD/Vqff+07K2gN0WfNkMohmG+dVw==", + "version": "0.14.54", + "resolved": "https://registry.npmjs.org/esbuild-windows-64/-/esbuild-windows-64-0.14.54.tgz", + "integrity": "sha512-AoHTRBUuYwXtZhjXZbA1pGfTo8cJo3vZIcWGLiUcTNgHpJJMC1rVA44ZereBHMJtotyN71S8Qw0npiCIkW96cQ==", "cpu": [ "x64" ], @@ -2534,9 +2614,9 @@ } }, "node_modules/esbuild-windows-arm64": { - "version": "0.14.49", - "resolved": "https://registry.npmjs.org/esbuild-windows-arm64/-/esbuild-windows-arm64-0.14.49.tgz", - "integrity": "sha512-v+HYNAXzuANrCbbLFJ5nmO3m5y2PGZWLe3uloAkLt87aXiO2mZr3BTmacZdjwNkNEHuH3bNtN8cak+mzVjVPfA==", + "version": "0.14.54", + "resolved": "https://registry.npmjs.org/esbuild-windows-arm64/-/esbuild-windows-arm64-0.14.54.tgz", + "integrity": "sha512-M0kuUvXhot1zOISQGXwWn6YtS+Y/1RT9WrVIOywZnJHo3jCDyewAc79aKNQWFCQm+xNHVTq9h8dZKvygoXQQRg==", "cpu": [ "arm64" ], @@ -2571,13 +2651,15 @@ } }, "node_modules/eslint": { - "version": "8.19.0", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.19.0.tgz", - "integrity": "sha512-SXOPj3x9VKvPe81TjjUJCYlV4oJjQw68Uek+AM0X4p+33dj2HY5bpTZOgnQHcG2eAm1mtCU9uNMnJi7exU/kYw==", + "version": "8.26.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.26.0.tgz", + "integrity": "sha512-kzJkpaw1Bfwheq4VXUezFriD1GxszX6dUekM7Z3aC2o4hju+tsR/XyTC3RcoSD7jmy9VkPU3+N6YjVU2e96Oyg==", "dev": true, "dependencies": { - "@eslint/eslintrc": "^1.3.0", - "@humanwhocodes/config-array": "^0.9.2", + "@eslint/eslintrc": "^1.3.3", + "@humanwhocodes/config-array": "^0.11.6", + "@humanwhocodes/module-importer": "^1.0.1", + "@nodelib/fs.walk": "^1.2.8", "ajv": "^6.10.0", "chalk": "^4.0.0", "cross-spawn": "^7.0.2", @@ -2587,18 +2669,21 @@ "eslint-scope": "^7.1.1", "eslint-utils": "^3.0.0", "eslint-visitor-keys": "^3.3.0", - "espree": "^9.3.2", + "espree": "^9.4.0", "esquery": "^1.4.0", "esutils": "^2.0.2", "fast-deep-equal": "^3.1.3", "file-entry-cache": "^6.0.1", - "functional-red-black-tree": "^1.0.1", - "glob-parent": "^6.0.1", + "find-up": "^5.0.0", + "glob-parent": "^6.0.2", "globals": "^13.15.0", + "grapheme-splitter": "^1.0.4", "ignore": "^5.2.0", "import-fresh": "^3.0.0", "imurmurhash": "^0.1.4", "is-glob": "^4.0.0", + "is-path-inside": "^3.0.3", + "js-sdsl": "^4.1.4", "js-yaml": "^4.1.0", "json-stable-stringify-without-jsonify": "^1.0.1", "levn": "^0.4.1", @@ -2609,8 +2694,7 @@ "regexpp": "^3.2.0", "strip-ansi": "^6.0.1", "strip-json-comments": "^3.1.0", - "text-table": "^0.2.0", - "v8-compile-cache": "^2.0.3" + "text-table": "^0.2.0" }, "bin": { "eslint": "bin/eslint.js" @@ -2623,26 +2707,26 @@ } }, "node_modules/eslint-plugin-tsdoc": { - "version": "0.2.16", - "resolved": "https://registry.npmjs.org/eslint-plugin-tsdoc/-/eslint-plugin-tsdoc-0.2.16.tgz", - "integrity": "sha512-F/RWMnyDQuGlg82vQEFHQtGyWi7++XJKdYNn0ulIbyMOFqYIjoJOUdE6olORxgwgLkpJxsCJpJbTHgxJ/ggfXw==", + "version": "0.2.17", + "resolved": "https://registry.npmjs.org/eslint-plugin-tsdoc/-/eslint-plugin-tsdoc-0.2.17.tgz", + "integrity": "sha512-xRmVi7Zx44lOBuYqG8vzTXuL6IdGOeF9nHX17bjJ8+VE6fsxpdGem0/SBTmAwgYMKYB1WBkqRJVQ+n8GK041pA==", "dev": true, "dependencies": { - "@microsoft/tsdoc": "0.14.1", - "@microsoft/tsdoc-config": "0.16.1" + "@microsoft/tsdoc": "0.14.2", + "@microsoft/tsdoc-config": "0.16.2" } }, "node_modules/eslint-scope": { - "version": "7.1.1", - "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.1.1.tgz", - "integrity": "sha512-QKQM/UXpIiHcLqJ5AOyIW7XZmzjkzQXYE54n1++wb0u9V/abW3l9uQnxX8Z5Xd18xyKIMTUAyQ0k1e8pz6LUrw==", + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz", + "integrity": "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==", "dev": true, "dependencies": { "esrecurse": "^4.3.0", - "estraverse": "^5.2.0" + "estraverse": "^4.1.1" }, "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + "node": ">=8.0.0" } }, "node_modules/eslint-utils": { @@ -2681,18 +2765,43 @@ "node": "^12.22.0 || ^14.17.0 || >=16.0.0" } }, - "node_modules/espree": { - "version": "9.3.2", - "resolved": "https://registry.npmjs.org/espree/-/espree-9.3.2.tgz", - "integrity": "sha512-D211tC7ZwouTIuY5x9XnS0E9sWNChB7IYKX/Xp5eQj3nFXhqmiUDB9q27y76oFl8jTg3pXcQx/bpxMfs3CIZbA==", + "node_modules/eslint/node_modules/eslint-scope": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.1.1.tgz", + "integrity": "sha512-QKQM/UXpIiHcLqJ5AOyIW7XZmzjkzQXYE54n1++wb0u9V/abW3l9uQnxX8Z5Xd18xyKIMTUAyQ0k1e8pz6LUrw==", "dev": true, "dependencies": { - "acorn": "^8.7.1", + "esrecurse": "^4.3.0", + "estraverse": "^5.2.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + } + }, + "node_modules/eslint/node_modules/estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "dev": true, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/espree": { + "version": "9.4.1", + "resolved": "https://registry.npmjs.org/espree/-/espree-9.4.1.tgz", + "integrity": "sha512-XwctdmTO6SIvCzd9810yyNzIrOrqNYV9Koizx4C/mRhf9uq0o4yHoCEU/670pOxOL/MSraektvSAji79kX90Vg==", + "dev": true, + "dependencies": { + "acorn": "^8.8.0", "acorn-jsx": "^5.3.2", "eslint-visitor-keys": "^3.3.0" }, "engines": { "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" } }, "node_modules/esprima": { @@ -2720,6 +2829,15 @@ "node": ">=0.10" } }, + "node_modules/esquery/node_modules/estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "dev": true, + "engines": { + "node": ">=4.0" + } + }, "node_modules/esrecurse": { "version": "4.3.0", "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", @@ -2732,7 +2850,7 @@ "node": ">=4.0" } }, - "node_modules/estraverse": { + "node_modules/esrecurse/node_modules/estraverse": { "version": "5.3.0", "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", @@ -2741,6 +2859,15 @@ "node": ">=4.0" } }, + "node_modules/estraverse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", + "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", + "dev": true, + "engines": { + "node": ">=4.0" + } + }, "node_modules/esutils": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", @@ -2805,9 +2932,9 @@ "dev": true }, "node_modules/fast-glob": { - "version": "3.2.11", - "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.11.tgz", - "integrity": "sha512-xrO3+1bxSo3ZVHAnqzyuewYT6aMFHRAd4Kcs92MAonjwQZLsK9d0SF1IyQ3k5PoirxTW0Oe/RqFgMQ6TcNE5Ew==", + "version": "3.2.12", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.12.tgz", + "integrity": "sha512-DVj4CQIYYow0BlaelwK1pHl5n5cRSJfM60UA0zK891sVInoPri2Ekj7+e1CT3/3qxXenpI+nBBmQAcJPJgaj4w==", "dev": true, "dependencies": { "@nodelib/fs.stat": "^2.0.2", @@ -2854,9 +2981,9 @@ } }, "node_modules/fb-watchman": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/fb-watchman/-/fb-watchman-2.0.1.tgz", - "integrity": "sha512-DkPJKQeY6kKwmuMretBhr7G6Vodr7bFwDYTXIkfG1gjvNpaxBTQV3PbXg6bR1c1UP4jPOX0jHUbbHANL9vRjVg==", + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/fb-watchman/-/fb-watchman-2.0.2.tgz", + "integrity": "sha512-p5161BqbuCaSnB8jIbzQHOlpgsPmK5rJVDfDKO91Axs5NC1uu3HRQm6wt9cd9/+GtQQIO53JdGXXoyDpTAsgYA==", "dev": true, "dependencies": { "bser": "2.1.1" @@ -2887,16 +3014,19 @@ } }, "node_modules/find-up": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", - "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", + "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", "dev": true, "dependencies": { - "locate-path": "^5.0.0", + "locate-path": "^6.0.0", "path-exists": "^4.0.0" }, "engines": { - "node": ">=8" + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/flat-cache": { @@ -2913,9 +3043,9 @@ } }, "node_modules/flatted": { - "version": "3.2.6", - "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.2.6.tgz", - "integrity": "sha512-0sQoMh9s0BYsm+12Huy/rkKxVu4R1+r96YX5cG44rHV0pQ6iC3Q+mkoMFaGWObMFYQxCVT+ssG1ksneA2MI9KQ==", + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.2.7.tgz", + "integrity": "sha512-5nqDSxl8nn5BSNxyR3n4I6eDmbolI6WT+QqR547RwxQapgjQBmtktdP+HTBb/a/zLsbzERTONyUB5pefh5TtjQ==", "dev": true }, "node_modules/fs.realpath": { @@ -2944,12 +3074,6 @@ "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==", "dev": true }, - "node_modules/functional-red-black-tree": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz", - "integrity": "sha512-dsKNQNdj6xA3T+QlADDA7mOSlX0qiMINjn0cgr+eGHGsbSHzTabcIogz2+p/iqP1Xs6EP/sS2SbqH+brGTbq0g==", - "dev": true - }, "node_modules/gensync": { "version": "1.0.0-beta.2", "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", @@ -3042,9 +3166,9 @@ } }, "node_modules/globals": { - "version": "13.16.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-13.16.0.tgz", - "integrity": "sha512-A1lrQfpNF+McdPOnnFqY3kSN0AFTy485bTi1bkLk4mVPODIUEcSfhHgRqA+QdXPksrSTTztYXx37NFV+GpGk3Q==", + "version": "13.17.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-13.17.0.tgz", + "integrity": "sha512-1C+6nQRb1GwGMKm2dH/E7enFAMxGTmGI7/dEdhy/DNelv85w9B72t3uc5frtMNXIbzrarJJ/lTCjcaZwbLJmyw==", "dev": true, "dependencies": { "type-fest": "^0.20.2" @@ -3082,6 +3206,12 @@ "integrity": "sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA==", "dev": true }, + "node_modules/grapheme-splitter": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/grapheme-splitter/-/grapheme-splitter-1.0.4.tgz", + "integrity": "sha512-bzh50DW9kTPM00T8y4o8vQg89Di9oLJVLW/KaOGIXJWP/iqCN6WKYkbNOF04vFLJhwcpYUh9ydh/+5vpOqV4YQ==", + "dev": true + }, "node_modules/has": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", @@ -3212,9 +3342,9 @@ "dev": true }, "node_modules/is-core-module": { - "version": "2.9.0", - "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.9.0.tgz", - "integrity": "sha512-+5FPy5PnwmO3lvfMb0AsoPaBG+5KHUI0wYFXOtYPnVVVspTFUuMZNfNaNVRt3FZadstu2c8x23vykRW/NBoU6A==", + "version": "2.11.0", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.11.0.tgz", + "integrity": "sha512-RRjxlvLDkD1YJwDbroBHMb+cukurkDWNyHx7D3oNB5x9rb5ogcksMC5wHCadcXoo67gVr/+3GFySh3134zi6rw==", "dev": true, "dependencies": { "has": "^1.0.3" @@ -3271,6 +3401,15 @@ "node": ">=0.12.0" } }, + "node_modules/is-path-inside": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-3.0.3.tgz", + "integrity": "sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, "node_modules/is-stream": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", @@ -3299,9 +3438,9 @@ } }, "node_modules/istanbul-lib-instrument": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-5.2.0.tgz", - "integrity": "sha512-6Lthe1hqXHBNsqvgDzGO6l03XNeu3CrG4RqQ1KM9+l5+jNGpEJfIELx1NS3SEHmJQA8np/u+E4EPRKRiu6m19A==", + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-5.2.1.tgz", + "integrity": "sha512-pzqtp31nLv/XFOzXGuvhCb8qhjmTVo5vjVk19XE4CRlSWz0KoeJ3bw9XsA7nOp9YBf4qHjwBxkDzKcME/J29Yg==", "dev": true, "dependencies": { "@babel/core": "^7.12.3", @@ -3746,6 +3885,23 @@ "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" } }, + "node_modules/jest-resolve/node_modules/resolve": { + "version": "1.22.1", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.1.tgz", + "integrity": "sha512-nBpuuYuY5jFsli/JIs1oldw6fOQCBioohqWZg/2hiaOybXOft4lonv85uDOKXdf8rhyK159cxU5cDcK/NKk8zw==", + "dev": true, + "dependencies": { + "is-core-module": "^2.9.0", + "path-parse": "^1.0.7", + "supports-preserve-symlinks-flag": "^1.0.0" + }, + "bin": { + "resolve": "bin/resolve" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/jest-runner": { "version": "28.1.3", "resolved": "https://registry.npmjs.org/jest-runner/-/jest-runner-28.1.3.tgz", @@ -3976,6 +4132,12 @@ "integrity": "sha512-8wb9Yw966OSxApiCt0K3yNJL8pnNeIv+OEq2YMidz4FKP6nonSRoOXc80iXY4JaN2FC11B9qsNmDsm+ZOfMROA==", "dev": true }, + "node_modules/js-sdsl": { + "version": "4.1.5", + "resolved": "https://registry.npmjs.org/js-sdsl/-/js-sdsl-4.1.5.tgz", + "integrity": "sha512-08bOAKweV2NUC1wqTtf3qZlnpOX/R2DU9ikpjOHs0H+ibQv3zpncVQg6um4uYtRtrwIX8M4Nh3ytK4HGlYAq7Q==", + "dev": true + }, "node_modules/js-tokens": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", @@ -4074,9 +4236,9 @@ "dev": true }, "node_modules/linkedom": { - "version": "0.14.12", - "resolved": "https://registry.npmjs.org/linkedom/-/linkedom-0.14.12.tgz", - "integrity": "sha512-8uw8LZifCwyWeVWr80T79sQTMmNXt4Da7oN5yH5gTXRqQM+TuZWJyBqRMcIp32zx/f8anHNHyil9Avw9y76ziQ==", + "version": "0.14.19", + "resolved": "https://registry.npmjs.org/linkedom/-/linkedom-0.14.19.tgz", + "integrity": "sha512-sFNkQZlKBWpEaAcbsDIghTLE0hHbyvS6dZuM7IH+KTM09GaQ772PtDZAuFlN0oFgyAjUj8XS9FpoWSLmBjl8MA==", "dependencies": { "css-select": "^5.1.0", "cssom": "^0.5.0", @@ -4091,15 +4253,18 @@ "integrity": "sha512-RuMffC89BOWQoY0WKGpIhn5gX3iI54O6nRA0yC124NYVtzjmFWBIiFd8M0x+ZdX0P9R4lADg1mgP8C7PxGOWuQ==" }, "node_modules/locate-path": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", - "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", + "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", "dev": true, "dependencies": { - "p-locate": "^4.1.0" + "p-locate": "^5.0.0" }, "engines": { - "node": ">=8" + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/lodash.memoize": { @@ -4226,6 +4391,12 @@ "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", "dev": true }, + "node_modules/natural-compare-lite": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/natural-compare-lite/-/natural-compare-lite-1.4.0.tgz", + "integrity": "sha512-Tj+HTDSJJKaZnfiuw+iaF9skdPpTo2GtEly5JHnWV/hfv2Qj/9RKsGISQtLh2ox3l5EAGw487hnBee0sIJ6v2g==", + "dev": true + }, "node_modules/node-int64": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/node-int64/-/node-int64-0.4.0.tgz", @@ -4327,27 +4498,15 @@ } }, "node_modules/p-locate": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", - "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", + "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", "dev": true, "dependencies": { - "p-limit": "^2.2.0" + "p-limit": "^3.0.2" }, "engines": { - "node": ">=8" - } - }, - "node_modules/p-locate/node_modules/p-limit": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", - "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", - "dev": true, - "dependencies": { - "p-try": "^2.0.0" - }, - "engines": { - "node": ">=6" + "node": ">=10" }, "funding": { "url": "https://github.com/sponsors/sindresorhus" @@ -4473,6 +4632,58 @@ "node": ">=8" } }, + "node_modules/pkg-dir/node_modules/find-up": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", + "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", + "dev": true, + "dependencies": { + "locate-path": "^5.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/pkg-dir/node_modules/locate-path": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", + "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", + "dev": true, + "dependencies": { + "p-locate": "^4.1.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/pkg-dir/node_modules/p-limit": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", + "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", + "dev": true, + "dependencies": { + "p-try": "^2.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/pkg-dir/node_modules/p-locate": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", + "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", + "dev": true, + "dependencies": { + "p-limit": "^2.2.0" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/prelude-ls": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", @@ -4579,17 +4790,13 @@ } }, "node_modules/resolve": { - "version": "1.22.1", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.1.tgz", - "integrity": "sha512-nBpuuYuY5jFsli/JIs1oldw6fOQCBioohqWZg/2hiaOybXOft4lonv85uDOKXdf8rhyK159cxU5cDcK/NKk8zw==", + "version": "1.19.0", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.19.0.tgz", + "integrity": "sha512-rArEXAgsBG4UgRGcynxWIWKFvh/XZCcS8UJdHhwy91zwAvCZIbcs+vAbflgBnNjYMs/i/i+/Ux6IZhML1yPvxg==", "dev": true, "dependencies": { - "is-core-module": "^2.9.0", - "path-parse": "^1.0.7", - "supports-preserve-symlinks-flag": "^1.0.0" - }, - "bin": { - "resolve": "bin/resolve" + "is-core-module": "^2.1.0", + "path-parse": "^1.0.6" }, "funding": { "url": "https://github.com/sponsors/ljharb" @@ -4702,16 +4909,10 @@ "queue-microtask": "^1.2.2" } }, - "node_modules/safe-buffer": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", - "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", - "dev": true - }, "node_modules/semver": { - "version": "7.3.7", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.7.tgz", - "integrity": "sha512-QlYTucUYOews+WeEujDoEGziz4K6c47V/Bd+LjSSYcA94p+DmINdf7ncaUinThfvZyu13lN9OY1XDxt8C0Tw0g==", + "version": "7.3.8", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.8.tgz", + "integrity": "sha512-NB1ctGL5rlHrPJtFDVIVzTyQylMLu9N9VICA6HSFJo8MCGVTMW6gfpicwKmmK/dAjTOrqu5l63JJOpDSrAis3A==", "dev": true, "dependencies": { "lru-cache": "^6.0.0" @@ -4811,6 +5012,14 @@ "node": ">=8" } }, + "node_modules/streamsearch": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/streamsearch/-/streamsearch-1.1.0.tgz", + "integrity": "sha512-Mcc5wHehp9aXz1ax6bZUyY5afg9u2rv5cqQI3mRrYkGC8rW2hM02jWuwjtL++LS5qinSyhj2QfLyNsuc+VsExg==", + "engines": { + "node": ">=10.0.0" + } + }, "node_modules/string-length": { "version": "4.0.2", "resolved": "https://registry.npmjs.org/string-length/-/string-length-4.0.2.tgz", @@ -4893,9 +5102,9 @@ } }, "node_modules/supports-hyperlinks": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/supports-hyperlinks/-/supports-hyperlinks-2.2.0.tgz", - "integrity": "sha512-6sXEzV5+I5j8Bmq9/vUphGRM/RJNT9SCURJLjwfOg51heRtguGWDzcaBlgAzKhQa0EVNpPEKzQuBwZ8S8WaCeQ==", + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/supports-hyperlinks/-/supports-hyperlinks-2.3.0.tgz", + "integrity": "sha512-RpsAZlpWcDwOPQA22aCH4J0t7L8JmAvsCxfOSEwm7cQs3LshN36QaTkwd70DnBOXDWGssw2eUoc8CaRWT0XunA==", "dev": true, "dependencies": { "has-flag": "^4.0.0", @@ -5098,9 +5307,9 @@ } }, "node_modules/typescript": { - "version": "4.7.4", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.7.4.tgz", - "integrity": "sha512-C0WQT0gezHuw6AdY1M2jxUO83Rjf0HP7Sk1DtXj6j1EwkQNZrHAg2XPWlq62oqEhYvONq5pkC2Y9oPljWToLmQ==", + "version": "4.8.4", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.8.4.tgz", + "integrity": "sha512-QCh+85mCy+h0IGff8r5XWzOVSbBO+KfeYrMQh7NJ58QujwcE22u+NUSmUxqF+un70P9GXKxa2HCNiTTMJknyjQ==", "dev": true, "bin": { "tsc": "bin/tsc", @@ -5116,17 +5325,20 @@ "integrity": "sha512-o0QVGuFg24FK765Qdd5kk0zU/U4dEsCtN/GSiwNI9i8xsSVtjIAOdTaVhLwZ1nrbWxFVMxNDDl+9fednsOMsBw==" }, "node_modules/undici": { - "version": "5.8.2", - "resolved": "https://registry.npmjs.org/undici/-/undici-5.8.2.tgz", - "integrity": "sha512-3KLq3pXMS0Y4IELV045fTxqz04Nk9Ms7yfBBHum3yxsTR4XNn+ZCaUbf/mWitgYDAhsplQ0B1G4S5D345lMO3A==", + "version": "5.12.0", + "resolved": "https://registry.npmjs.org/undici/-/undici-5.12.0.tgz", + "integrity": "sha512-zMLamCG62PGjd9HHMpo05bSLvvwWOZgGeiWlN/vlqu3+lRo3elxktVGEyLMX+IO7c2eflLjcW74AlkhEZm15mg==", + "dependencies": { + "busboy": "^1.6.0" + }, "engines": { "node": ">=12.18" } }, "node_modules/update-browserslist-db": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.4.tgz", - "integrity": "sha512-jnmO2BEGUjsMOe/Fg9u0oczOe/ppIDZPebzccl1yDWGLFP16Pa1/RM5wEoKYPG2zstNcDuAStejyxsOuKINdGA==", + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.10.tgz", + "integrity": "sha512-OztqDenkfFkbSG+tRxBeAnCVPckDBcvibKd35yDONx6OU8N7sqgwc7rCbkJ/WcYtVRZ4ba68d6byhC21GFh7sQ==", "dev": true, "funding": [ { @@ -5158,12 +5370,6 @@ "punycode": "^2.1.0" } }, - "node_modules/v8-compile-cache": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/v8-compile-cache/-/v8-compile-cache-2.3.0.tgz", - "integrity": "sha512-l8lCEmLcLYZh4nbunNZvQCJc5pv7+RCwa8q/LdUx8u7lsWvPDKmpodJAJNwkAhJC//dFY48KuIEmjtd4RViDrA==", - "dev": true - }, "node_modules/v8-to-istanbul": { "version": "9.0.1", "resolved": "https://registry.npmjs.org/v8-to-istanbul/-/v8-to-istanbul-9.0.1.tgz", @@ -5235,16 +5441,16 @@ "dev": true }, "node_modules/write-file-atomic": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-4.0.1.tgz", - "integrity": "sha512-nSKUxgAbyioruk6hU87QzVbY279oYT6uiwgDoujth2ju4mJ+TZau7SQBhtbTmUyuNYTuXnSyRn66FV0+eCgcrQ==", + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-4.0.2.tgz", + "integrity": "sha512-7KxauUdBmSdWnmpaGFg+ppNjKF8uNLry8LyzjauQDOVONfFLNKrKvQOxZ/VuTIcS/gge/YNahf5RIIQWTSarlg==", "dev": true, "dependencies": { "imurmurhash": "^0.1.4", "signal-exit": "^3.0.7" }, "engines": { - "node": "^12.13.0 || ^14.15.0 || >=16" + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" } }, "node_modules/y18n": { @@ -5263,27 +5469,27 @@ "dev": true }, "node_modules/yargs": { - "version": "17.5.1", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.5.1.tgz", - "integrity": "sha512-t6YAJcxDkNX7NFYiVtKvWUz8l+PaKTLiL63mJYWR2GnHq2gjEWISzsLp9wg3aY36dY1j+gfIEL3pIF+XlJJfbA==", + "version": "17.6.2", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.6.2.tgz", + "integrity": "sha512-1/9UrdHjDZc0eOU0HxOHoS78C69UD3JRMvzlJ7S79S2nTaWRA/whGCTV8o9e/N/1Va9YIV7Q4sOxD8VV4pCWOw==", "dev": true, "dependencies": { - "cliui": "^7.0.2", + "cliui": "^8.0.1", "escalade": "^3.1.1", "get-caller-file": "^2.0.5", "require-directory": "^2.1.1", "string-width": "^4.2.3", "y18n": "^5.0.5", - "yargs-parser": "^21.0.0" + "yargs-parser": "^21.1.1" }, "engines": { "node": ">=12" } }, "node_modules/yargs-parser": { - "version": "21.0.1", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.0.1.tgz", - "integrity": "sha512-9BK1jFpLzJROCI5TzwZL/TU4gqjK5xiHV/RfWLOahrjAko/e4DJkRDZQXfvqAsiZzzYhgAzbgz6lg48jcm4GLg==", + "version": "21.1.1", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz", + "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==", "dev": true, "engines": { "node": ">=12" @@ -5323,27 +5529,27 @@ } }, "@babel/compat-data": { - "version": "7.18.8", - "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.18.8.tgz", - "integrity": "sha512-HSmX4WZPPK3FUxYp7g2T6EyO8j96HlZJlxmKPSh6KAcqwyDrfx7hKjXpAW/0FhFfTJsR0Yt4lAjLI2coMptIHQ==", + "version": "7.20.1", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.20.1.tgz", + "integrity": "sha512-EWZ4mE2diW3QALKvDMiXnbZpRvlj+nayZ112nK93SnhqOtpdsbVD4W+2tEoT3YNBAG9RBR0ISY758ZkOgsn6pQ==", "dev": true }, "@babel/core": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.18.6.tgz", - "integrity": "sha512-cQbWBpxcbbs/IUredIPkHiAGULLV8iwgNRMFzvbhEXISp4f3rUUXE5+TIw6KwUWUR3DwyI6gmBRnmAtYaWehwQ==", + "version": "7.20.2", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.20.2.tgz", + "integrity": "sha512-w7DbG8DtMrJcFOi4VrLm+8QM4az8Mo+PuLBKLp2zrYRCow8W/f9xiXm5sN53C8HksCyDQwCKha9JiDoIyPjT2g==", "dev": true, "requires": { "@ampproject/remapping": "^2.1.0", "@babel/code-frame": "^7.18.6", - "@babel/generator": "^7.18.6", - "@babel/helper-compilation-targets": "^7.18.6", - "@babel/helper-module-transforms": "^7.18.6", - "@babel/helpers": "^7.18.6", - "@babel/parser": "^7.18.6", - "@babel/template": "^7.18.6", - "@babel/traverse": "^7.18.6", - "@babel/types": "^7.18.6", + "@babel/generator": "^7.20.2", + "@babel/helper-compilation-targets": "^7.20.0", + "@babel/helper-module-transforms": "^7.20.2", + "@babel/helpers": "^7.20.1", + "@babel/parser": "^7.20.2", + "@babel/template": "^7.18.10", + "@babel/traverse": "^7.20.1", + "@babel/types": "^7.20.2", "convert-source-map": "^1.7.0", "debug": "^4.1.0", "gensync": "^1.0.0-beta.2", @@ -5360,12 +5566,12 @@ } }, "@babel/generator": { - "version": "7.18.7", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.18.7.tgz", - "integrity": "sha512-shck+7VLlY72a2w9c3zYWuE1pwOKEiQHV7GTUbSnhyl5eu3i04t30tBY82ZRWrDfo3gkakCFtevExnxbkf2a3A==", + "version": "7.20.2", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.20.2.tgz", + "integrity": "sha512-SD75PMIK6i9H8G/tfGvB4KKl4Nw6Ssos9nGgYwxbgyTP0iX/Z55DveoH86rmUB/YHTQQ+ZC0F7xxaY8l2OF44Q==", "dev": true, "requires": { - "@babel/types": "^7.18.7", + "@babel/types": "^7.20.2", "@jridgewell/gen-mapping": "^0.3.2", "jsesc": "^2.5.1" }, @@ -5384,14 +5590,14 @@ } }, "@babel/helper-compilation-targets": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.18.6.tgz", - "integrity": "sha512-vFjbfhNCzqdeAtZflUFrG5YIFqGTqsctrtkZ1D/NB0mDW9TwW3GmmUepYY4G9wCET5rY5ugz4OGTcLd614IzQg==", + "version": "7.20.0", + "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.20.0.tgz", + "integrity": "sha512-0jp//vDGp9e8hZzBc6N/KwA5ZK3Wsm/pfm4CrY7vzegkVxc65SgSn6wYOnwHe9Js9HRQ1YTCKLGPzDtaS3RoLQ==", "dev": true, "requires": { - "@babel/compat-data": "^7.18.6", + "@babel/compat-data": "^7.20.0", "@babel/helper-validator-option": "^7.18.6", - "browserslist": "^4.20.2", + "browserslist": "^4.21.3", "semver": "^6.3.0" }, "dependencies": { @@ -5404,19 +5610,19 @@ } }, "@babel/helper-environment-visitor": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.18.6.tgz", - "integrity": "sha512-8n6gSfn2baOY+qlp+VSzsosjCVGFqWKmDF0cCWOybh52Dw3SEyoWR1KrhMJASjLwIEkkAufZ0xvr+SxLHSpy2Q==", + "version": "7.18.9", + "resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.18.9.tgz", + "integrity": "sha512-3r/aACDJ3fhQ/EVgFy0hpj8oHyHpQc+LPtJoY9SzTThAsStm4Ptegq92vqKoE3vD706ZVFWITnMnxucw+S9Ipg==", "dev": true }, "@babel/helper-function-name": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.18.6.tgz", - "integrity": "sha512-0mWMxV1aC97dhjCah5U5Ua7668r5ZmSC2DLfH2EZnf9c3/dHZKiFa5pRLMH5tjSl471tY6496ZWk/kjNONBxhw==", + "version": "7.19.0", + "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.19.0.tgz", + "integrity": "sha512-WAwHBINyrpqywkUH0nTnNgI5ina5TFn85HKS0pbPDfxFfhyR/aNQEn4hGi1P1JyT//I0t4OgXUlofzWILRvS5w==", "dev": true, "requires": { - "@babel/template": "^7.18.6", - "@babel/types": "^7.18.6" + "@babel/template": "^7.18.10", + "@babel/types": "^7.19.0" } }, "@babel/helper-hoist-variables": { @@ -5438,34 +5644,34 @@ } }, "@babel/helper-module-transforms": { - "version": "7.18.8", - "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.18.8.tgz", - "integrity": "sha512-che3jvZwIcZxrwh63VfnFTUzcAM9v/lznYkkRxIBGMPt1SudOKHAEec0SIRCfiuIzTcF7VGj/CaTT6gY4eWxvA==", + "version": "7.20.2", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.20.2.tgz", + "integrity": "sha512-zvBKyJXRbmK07XhMuujYoJ48B5yvvmM6+wcpv6Ivj4Yg6qO7NOZOSnvZN9CRl1zz1Z4cKf8YejmCMh8clOoOeA==", "dev": true, "requires": { - "@babel/helper-environment-visitor": "^7.18.6", + "@babel/helper-environment-visitor": "^7.18.9", "@babel/helper-module-imports": "^7.18.6", - "@babel/helper-simple-access": "^7.18.6", + "@babel/helper-simple-access": "^7.20.2", "@babel/helper-split-export-declaration": "^7.18.6", - "@babel/helper-validator-identifier": "^7.18.6", - "@babel/template": "^7.18.6", - "@babel/traverse": "^7.18.8", - "@babel/types": "^7.18.8" + "@babel/helper-validator-identifier": "^7.19.1", + "@babel/template": "^7.18.10", + "@babel/traverse": "^7.20.1", + "@babel/types": "^7.20.2" } }, "@babel/helper-plugin-utils": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.18.6.tgz", - "integrity": "sha512-gvZnm1YAAxh13eJdkb9EWHBnF3eAub3XTLCZEehHT2kWxiKVRL64+ae5Y6Ivne0mVHmMYKT+xWgZO+gQhuLUBg==", + "version": "7.20.2", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.20.2.tgz", + "integrity": "sha512-8RvlJG2mj4huQ4pZ+rU9lqKi9ZKiRmuvGuM2HlWmkmgOhbs6zEAw6IEiJ5cQqGbDzGZOhwuOQNtZMi/ENLjZoQ==", "dev": true }, "@babel/helper-simple-access": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.18.6.tgz", - "integrity": "sha512-iNpIgTgyAvDQpDj76POqg+YEt8fPxx3yaNBg3S30dxNKm2SWfYhD0TGrK/Eu9wHpUW63VQU894TsTg+GLbUa1g==", + "version": "7.20.2", + "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.20.2.tgz", + "integrity": "sha512-+0woI/WPq59IrqDYbVGfshjT5Dmk/nnbdpcF8SnMhhXObpTq2KNBdLFRFrkVdbDOyUmHBCxzm5FHV1rACIkIbA==", "dev": true, "requires": { - "@babel/types": "^7.18.6" + "@babel/types": "^7.20.2" } }, "@babel/helper-split-export-declaration": { @@ -5477,10 +5683,16 @@ "@babel/types": "^7.18.6" } }, + "@babel/helper-string-parser": { + "version": "7.19.4", + "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.19.4.tgz", + "integrity": "sha512-nHtDoQcuqFmwYNYPz3Rah5ph2p8PFeFCsZk9A/48dPc/rGocJ5J3hAAZ7pb76VWX3fZKu+uEr/FhH5jLx7umrw==", + "dev": true + }, "@babel/helper-validator-identifier": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.18.6.tgz", - "integrity": "sha512-MmetCkz9ej86nJQV+sFCxoGGrUbU3q02kgLciwkrt9QqEB7cP39oKEY0PakknEO0Gu20SskMRi+AYZ3b1TpN9g==", + "version": "7.19.1", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.19.1.tgz", + "integrity": "sha512-awrNfaMtnHUr653GgGEs++LlAvW6w+DcPrOliSMXWCKo597CwL5Acf/wWdNkf/tfEQE3mjkeD1YOVZOUV/od1w==", "dev": true }, "@babel/helper-validator-option": { @@ -5490,14 +5702,14 @@ "dev": true }, "@babel/helpers": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.18.6.tgz", - "integrity": "sha512-vzSiiqbQOghPngUYt/zWGvK3LAsPhz55vc9XNN0xAl2gV4ieShI2OQli5duxWHD+72PZPTKAcfcZDE1Cwc5zsQ==", + "version": "7.20.1", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.20.1.tgz", + "integrity": "sha512-J77mUVaDTUJFZ5BpP6mMn6OIl3rEWymk2ZxDBQJUG3P+PbmyMcF3bYWvz0ma69Af1oobDqT/iAsvzhB58xhQUg==", "dev": true, "requires": { - "@babel/template": "^7.18.6", - "@babel/traverse": "^7.18.6", - "@babel/types": "^7.18.6" + "@babel/template": "^7.18.10", + "@babel/traverse": "^7.20.1", + "@babel/types": "^7.20.0" } }, "@babel/highlight": { @@ -5570,9 +5782,9 @@ } }, "@babel/parser": { - "version": "7.18.8", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.18.8.tgz", - "integrity": "sha512-RSKRfYX20dyH+elbJK2uqAkVyucL+xXzhqlMD5/ZXx+dAAwpyB7HsvnHe/ZUGOF+xLr5Wx9/JoXVTj6BQE2/oA==", + "version": "7.20.2", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.20.2.tgz", + "integrity": "sha512-afk318kh2uKbo7BEj2QtEi8HVCGrwHUffrYDy7dgVcSa2j9lY3LDjPzcyGdpX7xgm35aWqvciZJ4WKmdF/SxYg==", "dev": true }, "@babel/plugin-syntax-async-generators": { @@ -5684,39 +5896,39 @@ } }, "@babel/plugin-syntax-typescript": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.18.6.tgz", - "integrity": "sha512-mAWAuq4rvOepWCBid55JuRNvpTNf2UGVgoz4JV0fXEKolsVZDzsa4NqCef758WZJj/GDu0gVGItjKFiClTAmZA==", + "version": "7.20.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.20.0.tgz", + "integrity": "sha512-rd9TkG+u1CExzS4SM1BlMEhMXwFLKVjOAFFCDx9PbX5ycJWDoWMcwdJH9RhkPu1dOgn5TrxLot/Gx6lWFuAUNQ==", "dev": true, "requires": { - "@babel/helper-plugin-utils": "^7.18.6" + "@babel/helper-plugin-utils": "^7.19.0" } }, "@babel/template": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.18.6.tgz", - "integrity": "sha512-JoDWzPe+wgBsTTgdnIma3iHNFC7YVJoPssVBDjiHfNlyt4YcunDtcDOUmfVDfCK5MfdsaIoX9PkijPhjH3nYUw==", + "version": "7.18.10", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.18.10.tgz", + "integrity": "sha512-TI+rCtooWHr3QJ27kJxfjutghu44DLnasDMwpDqCXVTal9RLp3RSYNh4NdBrRP2cQAoG9A8juOQl6P6oZG4JxA==", "dev": true, "requires": { "@babel/code-frame": "^7.18.6", - "@babel/parser": "^7.18.6", - "@babel/types": "^7.18.6" + "@babel/parser": "^7.18.10", + "@babel/types": "^7.18.10" } }, "@babel/traverse": { - "version": "7.18.8", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.18.8.tgz", - "integrity": "sha512-UNg/AcSySJYR/+mIcJQDCv00T+AqRO7j/ZEJLzpaYtgM48rMg5MnkJgyNqkzo88+p4tfRvZJCEiwwfG6h4jkRg==", + "version": "7.20.1", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.20.1.tgz", + "integrity": "sha512-d3tN8fkVJwFLkHkBN479SOsw4DMZnz8cdbL/gvuDuzy3TS6Nfw80HuQqhw1pITbIruHyh7d1fMA47kWzmcUEGA==", "dev": true, "requires": { "@babel/code-frame": "^7.18.6", - "@babel/generator": "^7.18.7", - "@babel/helper-environment-visitor": "^7.18.6", - "@babel/helper-function-name": "^7.18.6", + "@babel/generator": "^7.20.1", + "@babel/helper-environment-visitor": "^7.18.9", + "@babel/helper-function-name": "^7.19.0", "@babel/helper-hoist-variables": "^7.18.6", "@babel/helper-split-export-declaration": "^7.18.6", - "@babel/parser": "^7.18.8", - "@babel/types": "^7.18.8", + "@babel/parser": "^7.20.1", + "@babel/types": "^7.20.0", "debug": "^4.1.0", "globals": "^11.1.0" }, @@ -5730,12 +5942,13 @@ } }, "@babel/types": { - "version": "7.18.8", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.18.8.tgz", - "integrity": "sha512-qwpdsmraq0aJ3osLJRApsc2ouSJCdnMeZwB0DhbtHAtRpZNZCdlbRnHIgcRKzdE1g0iOGg644fzjOBcdOz9cPw==", + "version": "7.20.2", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.20.2.tgz", + "integrity": "sha512-FnnvsNWgZCr232sqtXggapvlkk/tuwR/qhGzcmxI0GXLCjmPYQPzio2FbdlWuY6y1sHFfQKk+rRbUZ9VStQMog==", "dev": true, "requires": { - "@babel/helper-validator-identifier": "^7.18.6", + "@babel/helper-string-parser": "^7.19.4", + "@babel/helper-validator-identifier": "^7.19.1", "to-fast-properties": "^2.0.0" } }, @@ -5745,15 +5958,22 @@ "integrity": "sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==", "dev": true }, + "@esbuild/linux-loong64": { + "version": "0.14.54", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.14.54.tgz", + "integrity": "sha512-bZBrLAIX1kpWelV0XemxBZllyRmM6vgFQQG2GdNb+r3Fkp0FOh1NJSvekXDs7jq70k4euu1cryLMfU+mTXlEpw==", + "dev": true, + "optional": true + }, "@eslint/eslintrc": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-1.3.0.tgz", - "integrity": "sha512-UWW0TMTmk2d7hLcWD1/e2g5HDM/HQ3csaLSqXCfqwh4uNDuNqlaKWXmEsL4Cs41Z0KnILNvwbHAah3C2yt06kw==", + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-1.3.3.tgz", + "integrity": "sha512-uj3pT6Mg+3t39fvLrj8iuCIJ38zKO9FpGtJ4BBJebJhEwjoT+KLVNCcHT5QC9NGRIEi7fZ0ZR8YRb884auB4Lg==", "dev": true, "requires": { "ajv": "^6.12.4", "debug": "^4.3.2", - "espree": "^9.3.2", + "espree": "^9.4.0", "globals": "^13.15.0", "ignore": "^5.2.0", "import-fresh": "^3.2.1", @@ -5763,16 +5983,22 @@ } }, "@humanwhocodes/config-array": { - "version": "0.9.5", - "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.9.5.tgz", - "integrity": "sha512-ObyMyWxZiCu/yTisA7uzx81s40xR2fD5Cg/2Kq7G02ajkNubJf6BopgDTmDyc3U7sXpNKM8cYOw7s7Tyr+DnCw==", + "version": "0.11.7", + "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.7.tgz", + "integrity": "sha512-kBbPWzN8oVMLb0hOUYXhmxggL/1cJE6ydvjDIGi9EnAGUyA7cLVKQg+d/Dsm+KZwx2czGHrCmMVLiyg8s5JPKw==", "dev": true, "requires": { "@humanwhocodes/object-schema": "^1.2.1", "debug": "^4.1.1", - "minimatch": "^3.0.4" + "minimatch": "^3.0.5" } }, + "@humanwhocodes/module-importer": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz", + "integrity": "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==", + "dev": true + }, "@humanwhocodes/object-schema": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-1.2.1.tgz", @@ -5801,6 +6027,16 @@ "sprintf-js": "~1.0.2" } }, + "find-up": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", + "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", + "dev": true, + "requires": { + "locate-path": "^5.0.0", + "path-exists": "^4.0.0" + } + }, "js-yaml": { "version": "3.14.1", "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz", @@ -5811,6 +6047,33 @@ "esprima": "^4.0.0" } }, + "locate-path": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", + "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", + "dev": true, + "requires": { + "p-locate": "^4.1.0" + } + }, + "p-limit": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", + "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", + "dev": true, + "requires": { + "p-try": "^2.0.0" + } + }, + "p-locate": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", + "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", + "dev": true, + "requires": { + "p-limit": "^2.2.0" + } + }, "resolve-from": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", @@ -6091,43 +6354,31 @@ "dev": true }, "@jridgewell/trace-mapping": { - "version": "0.3.14", - "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.14.tgz", - "integrity": "sha512-bJWEfQ9lPTvm3SneWwRFVLzrh6nhjwqw7TUFFBEMzwvg7t7PCDenf2lDwqo4NQXzdpgBXyFgDWnQA+2vkruksQ==", + "version": "0.3.17", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.17.tgz", + "integrity": "sha512-MCNzAp77qzKca9+W/+I0+sEpaUnZoeasnghNeVc41VZCEKaCH73Vq3BZZ/SzWIgrqE4H4ceI+p+b6C0mHf9T4g==", "dev": true, "requires": { - "@jridgewell/resolve-uri": "^3.0.3", - "@jridgewell/sourcemap-codec": "^1.4.10" + "@jridgewell/resolve-uri": "3.1.0", + "@jridgewell/sourcemap-codec": "1.4.14" } }, "@microsoft/tsdoc": { - "version": "0.14.1", - "resolved": "https://registry.npmjs.org/@microsoft/tsdoc/-/tsdoc-0.14.1.tgz", - "integrity": "sha512-6Wci+Tp3CgPt/B9B0a3J4s3yMgLNSku6w5TV6mN+61C71UqsRBv2FUibBf3tPGlNxebgPHMEUzKpb1ggE8KCKw==", + "version": "0.14.2", + "resolved": "https://registry.npmjs.org/@microsoft/tsdoc/-/tsdoc-0.14.2.tgz", + "integrity": "sha512-9b8mPpKrfeGRuhFH5iO1iwCLeIIsV6+H1sRfxbkoGXIyQE2BTsPd9zqSqQJ+pv5sJ/hT5M1zvOFL02MnEezFug==", "dev": true }, "@microsoft/tsdoc-config": { - "version": "0.16.1", - "resolved": "https://registry.npmjs.org/@microsoft/tsdoc-config/-/tsdoc-config-0.16.1.tgz", - "integrity": "sha512-2RqkwiD4uN6MLnHFljqBlZIXlt/SaUT6cuogU1w2ARw4nKuuppSmR0+s+NC+7kXBQykd9zzu0P4HtBpZT5zBpQ==", + "version": "0.16.2", + "resolved": "https://registry.npmjs.org/@microsoft/tsdoc-config/-/tsdoc-config-0.16.2.tgz", + "integrity": "sha512-OGiIzzoBLgWWR0UdRJX98oYO+XKGf7tiK4Zk6tQ/E4IJqGCe7dvkTvgDZV5cFJUzLGDOjeAXrnZoA6QkVySuxw==", "dev": true, "requires": { - "@microsoft/tsdoc": "0.14.1", + "@microsoft/tsdoc": "0.14.2", "ajv": "~6.12.6", "jju": "~1.4.0", "resolve": "~1.19.0" - }, - "dependencies": { - "resolve": { - "version": "1.19.0", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.19.0.tgz", - "integrity": "sha512-rArEXAgsBG4UgRGcynxWIWKFvh/XZCcS8UJdHhwy91zwAvCZIbcs+vAbflgBnNjYMs/i/i+/Ux6IZhML1yPvxg==", - "dev": true, - "requires": { - "is-core-module": "^2.1.0", - "path-parse": "^1.0.6" - } - } } }, "@nodelib/fs.scandir": { @@ -6157,15 +6408,15 @@ } }, "@protobuf-ts/plugin": { - "version": "2.7.0", - "resolved": "https://registry.npmjs.org/@protobuf-ts/plugin/-/plugin-2.7.0.tgz", - "integrity": "sha512-NpZBNsu7pe9CyjayY+jphHqjV4Ya3rP0Q1ban41pRiFPyFF0G+bpKdChOYxN1gCRz9XQWU9OyMt6fiaAsDpFPA==", + "version": "2.8.1", + "resolved": "https://registry.npmjs.org/@protobuf-ts/plugin/-/plugin-2.8.1.tgz", + "integrity": "sha512-lacRdXJ9TkTbI28U0KApsnVqnxeq1aZftOdq6LNPQJaIzBrVRxrMkqnnGWGQFYe0Tr93OKeW4A2lLjTkn32CuA==", "dev": true, "requires": { - "@protobuf-ts/plugin-framework": "^2.7.0", - "@protobuf-ts/protoc": "^2.7.0", - "@protobuf-ts/runtime": "^2.7.0", - "@protobuf-ts/runtime-rpc": "^2.7.0", + "@protobuf-ts/plugin-framework": "^2.8.1", + "@protobuf-ts/protoc": "^2.8.1", + "@protobuf-ts/runtime": "^2.8.1", + "@protobuf-ts/runtime-rpc": "^2.8.1", "typescript": "^3.9" }, "dependencies": { @@ -6178,12 +6429,12 @@ } }, "@protobuf-ts/plugin-framework": { - "version": "2.7.0", - "resolved": "https://registry.npmjs.org/@protobuf-ts/plugin-framework/-/plugin-framework-2.7.0.tgz", - "integrity": "sha512-dnvgUVONeDRr0rv5Jyq4RXVLVZ/NdQ/Boh+FwUFddMesM2EqN/z2vwpNZhraym4Z1Oj27y0fqMMhzkh5e6eJrQ==", + "version": "2.8.1", + "resolved": "https://registry.npmjs.org/@protobuf-ts/plugin-framework/-/plugin-framework-2.8.1.tgz", + "integrity": "sha512-hfLoYIyxCI6Ro6LY1BltNBDcXWL+36SwnWR/hcF4ttPHLE3rMIpYbz4IwQsfeU2SKbBeGFhZv9rcnDJB22cXog==", "dev": true, "requires": { - "@protobuf-ts/runtime": "^2.7.0", + "@protobuf-ts/runtime": "^2.8.1", "typescript": "^3.9" }, "dependencies": { @@ -6196,35 +6447,35 @@ } }, "@protobuf-ts/protoc": { - "version": "2.7.0", - "resolved": "https://registry.npmjs.org/@protobuf-ts/protoc/-/protoc-2.7.0.tgz", - "integrity": "sha512-YW61nbX9d3mWF44193S+bmWth5eFHxvrePQMUfdY8eEa3PTmhAUwgVCUBeCXEVUWgz1H/E0CnwdjlJgW4vQtOg==", + "version": "2.8.1", + "resolved": "https://registry.npmjs.org/@protobuf-ts/protoc/-/protoc-2.8.1.tgz", + "integrity": "sha512-6fehuL9bS22zCgPBBlESZjnoA4fxAUkOjMcaFMJSlVpN6CDN2O+c/Mo1pCXaNDO7FAidMPj5yhz48Kws4kOXEA==", "dev": true }, "@protobuf-ts/runtime": { - "version": "2.7.0", - "resolved": "https://registry.npmjs.org/@protobuf-ts/runtime/-/runtime-2.7.0.tgz", - "integrity": "sha512-CzunTplg81oMkF9MnSYiX2WOdHnAyHKnokZncgOHm5bt8iEfFNnUsMSbsWUus/ulRNIZ9VAVMjutd96vmySQaw==" + "version": "2.8.1", + "resolved": "https://registry.npmjs.org/@protobuf-ts/runtime/-/runtime-2.8.1.tgz", + "integrity": "sha512-D9M5hSumYCovIfNllt7N6ODh4q+LrjiMWtNETvooaf+a2XheZJ7kgjFlsFghti0CFWwtA//of4JXQfw9hU+cCw==" }, "@protobuf-ts/runtime-rpc": { - "version": "2.7.0", - "resolved": "https://registry.npmjs.org/@protobuf-ts/runtime-rpc/-/runtime-rpc-2.7.0.tgz", - "integrity": "sha512-ha2HFJYLam1Zv04roq4MgYgdivoXv3s5uDQpr6jOAflAduNRWpB5IFegvPvtdc89j4xs7vuNPIGyZtP/MgYAXA==", + "version": "2.8.1", + "resolved": "https://registry.npmjs.org/@protobuf-ts/runtime-rpc/-/runtime-rpc-2.8.1.tgz", + "integrity": "sha512-hc+HJpoAu50by8aBS55UygcrzD8jAvRKWZMCRJ9XY3h9Gl2tciYysfzSH1SWtF6XOT/4b5CKnnmdMR3ad7uU5g==", "dev": true, "requires": { - "@protobuf-ts/runtime": "^2.7.0" + "@protobuf-ts/runtime": "^2.8.1" } }, "@sinclair/typebox": { - "version": "0.24.20", - "resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.24.20.tgz", - "integrity": "sha512-kVaO5aEFZb33nPMTZBxiPEkY+slxiPtqC7QX8f9B3eGOMBvEfuMfxp9DSTTCsRJPumPKjrge4yagyssO4q6qzQ==", + "version": "0.24.51", + "resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.24.51.tgz", + "integrity": "sha512-1P1OROm/rdubP5aFDSZQILU0vrLCJ4fvHt6EoqHEM+2D/G5MK3bIaymUKLit8Js9gbns5UyJnkP/TZROLw4tUA==", "dev": true }, "@sinonjs/commons": { - "version": "1.8.3", - "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-1.8.3.tgz", - "integrity": "sha512-xkNcLAn/wZaX14RPlwizcKicDk9G3F8m2nU3L7Ukm5zBgTwiT0wsoFAHx9Jq56fJA1z/7uKGtCRu16sOUCLIHQ==", + "version": "1.8.4", + "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-1.8.4.tgz", + "integrity": "sha512-RpmQdHVo8hCEHDVpO39zToS9jOhR6nw+/lQAzRNq9ErrGV9IeHM71XCn68svVl/euFeVW6BWX4p35gkhbOcSIQ==", "dev": true, "requires": { "type-detect": "4.0.8" @@ -6272,9 +6523,9 @@ } }, "@types/babel__traverse": { - "version": "7.17.1", - "resolved": "https://registry.npmjs.org/@types/babel__traverse/-/babel__traverse-7.17.1.tgz", - "integrity": "sha512-kVzjari1s2YVi77D3w1yuvohV2idweYXMCDzqBiVNN63TcDWrIlTVOYpqVrvbbyOE/IyzBoTKF0fdnLPEORFxA==", + "version": "7.18.2", + "resolved": "https://registry.npmjs.org/@types/babel__traverse/-/babel__traverse-7.18.2.tgz", + "integrity": "sha512-FcFaxOr2V5KZCviw1TnutEMVUVsGt4D2hP1TAfXZAMKuHYW3xQhe3jTxNPWutgCJ3/X1c5yX8ZoGVEItxKbwBg==", "dev": true, "requires": { "@babel/types": "^7.3.0" @@ -6314,9 +6565,9 @@ } }, "@types/jest": { - "version": "28.1.7", - "resolved": "https://registry.npmjs.org/@types/jest/-/jest-28.1.7.tgz", - "integrity": "sha512-acDN4VHD40V24tgu0iC44jchXavRNVFXQ/E6Z5XNsswgoSO/4NgsXoEYmPUGookKldlZQyIpmrEXsHI9cA3ZTA==", + "version": "28.1.8", + "resolved": "https://registry.npmjs.org/@types/jest/-/jest-28.1.8.tgz", + "integrity": "sha512-8TJkV++s7B6XqnDrzR1m/TT0A0h948Pnl/097veySPN67VRAgQ4gZ7n2KfJo2rVq6njQjdxU3GCCyDvAeuHoiw==", "dev": true, "requires": { "expect": "^28.0.0", @@ -6336,9 +6587,15 @@ "dev": true }, "@types/prettier": { - "version": "2.6.3", - "resolved": "https://registry.npmjs.org/@types/prettier/-/prettier-2.6.3.tgz", - "integrity": "sha512-ymZk3LEC/fsut+/Q5qejp6R9O1rMxz3XaRHDV6kX8MrGAhOSPqVARbDi+EZvInBpw+BnCX3TD240byVkOfQsHg==", + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/@types/prettier/-/prettier-2.7.1.tgz", + "integrity": "sha512-ri0UmynRRvZiiUJdiz38MmIblKK+oH30MztdBVR95dv/Ubw6neWSb8u1XpRb72L4qsZOhz+L+z9JD40SJmfWow==", + "dev": true + }, + "@types/semver": { + "version": "7.3.13", + "resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.3.13.tgz", + "integrity": "sha512-21cFJr9z3g5dW8B0CVI9g2O9beqaThGQ6ZFBqHfwhzLDKUxaqTIy3vnfah/UPkfOiF2pLq+tGz+W8RyCskuslw==", "dev": true }, "@types/stack-utils": { @@ -6348,9 +6605,9 @@ "dev": true }, "@types/yargs": { - "version": "17.0.10", - "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.10.tgz", - "integrity": "sha512-gmEaFwpj/7f/ROdtIlci1R1VYU1J4j95m8T+Tj3iBgiBFKg1foE/PSl93bBd5T9LDXNPo8UlNN6W0qwD8O5OaA==", + "version": "17.0.13", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.13.tgz", + "integrity": "sha512-9sWaruZk2JGxIQU+IhI1fhPYRcQ0UuTNuKuCW9bR5fp7qi2Llf7WDzNa17Cy7TKnh3cdxDOiyTu6gaLS0eDatg==", "dev": true, "requires": { "@types/yargs-parser": "*" @@ -6363,69 +6620,70 @@ "dev": true }, "@typescript-eslint/eslint-plugin": { - "version": "5.30.6", - "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.30.6.tgz", - "integrity": "sha512-J4zYMIhgrx4MgnZrSDD7sEnQp7FmhKNOaqaOpaoQ/SfdMfRB/0yvK74hTnvH+VQxndZynqs5/Hn4t+2/j9bADg==", + "version": "5.42.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.42.0.tgz", + "integrity": "sha512-5TJh2AgL6+wpL8H/GTSjNb4WrjKoR2rqvFxR/DDTqYNk6uXn8BJMEcncLSpMbf/XV1aS0jAjYwn98uvVCiAywQ==", "dev": true, "requires": { - "@typescript-eslint/scope-manager": "5.30.6", - "@typescript-eslint/type-utils": "5.30.6", - "@typescript-eslint/utils": "5.30.6", + "@typescript-eslint/scope-manager": "5.42.0", + "@typescript-eslint/type-utils": "5.42.0", + "@typescript-eslint/utils": "5.42.0", "debug": "^4.3.4", - "functional-red-black-tree": "^1.0.1", "ignore": "^5.2.0", + "natural-compare-lite": "^1.4.0", "regexpp": "^3.2.0", "semver": "^7.3.7", "tsutils": "^3.21.0" } }, "@typescript-eslint/parser": { - "version": "5.30.6", - "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-5.30.6.tgz", - "integrity": "sha512-gfF9lZjT0p2ZSdxO70Xbw8w9sPPJGfAdjK7WikEjB3fcUI/yr9maUVEdqigBjKincUYNKOmf7QBMiTf719kbrA==", + "version": "5.42.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-5.42.0.tgz", + "integrity": "sha512-Ixh9qrOTDRctFg3yIwrLkgf33AHyEIn6lhyf5cCfwwiGtkWhNpVKlEZApi3inGQR/barWnY7qY8FbGKBO7p3JA==", "dev": true, "requires": { - "@typescript-eslint/scope-manager": "5.30.6", - "@typescript-eslint/types": "5.30.6", - "@typescript-eslint/typescript-estree": "5.30.6", + "@typescript-eslint/scope-manager": "5.42.0", + "@typescript-eslint/types": "5.42.0", + "@typescript-eslint/typescript-estree": "5.42.0", "debug": "^4.3.4" } }, "@typescript-eslint/scope-manager": { - "version": "5.30.6", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.30.6.tgz", - "integrity": "sha512-Hkq5PhLgtVoW1obkqYH0i4iELctEKixkhWLPTYs55doGUKCASvkjOXOd/pisVeLdO24ZX9D6yymJ/twqpJiG3g==", + "version": "5.42.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.42.0.tgz", + "integrity": "sha512-l5/3IBHLH0Bv04y+H+zlcLiEMEMjWGaCX6WyHE5Uk2YkSGAMlgdUPsT/ywTSKgu9D1dmmKMYgYZijObfA39Wow==", "dev": true, "requires": { - "@typescript-eslint/types": "5.30.6", - "@typescript-eslint/visitor-keys": "5.30.6" + "@typescript-eslint/types": "5.42.0", + "@typescript-eslint/visitor-keys": "5.42.0" } }, "@typescript-eslint/type-utils": { - "version": "5.30.6", - "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-5.30.6.tgz", - "integrity": "sha512-GFVVzs2j0QPpM+NTDMXtNmJKlF842lkZKDSanIxf+ArJsGeZUIaeT4jGg+gAgHt7AcQSFwW7htzF/rbAh2jaVA==", + "version": "5.42.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-5.42.0.tgz", + "integrity": "sha512-HW14TXC45dFVZxnVW8rnUGnvYyRC0E/vxXShFCthcC9VhVTmjqOmtqj6H5rm9Zxv+ORxKA/1aLGD7vmlLsdlOg==", "dev": true, "requires": { - "@typescript-eslint/utils": "5.30.6", + "@typescript-eslint/typescript-estree": "5.42.0", + "@typescript-eslint/utils": "5.42.0", "debug": "^4.3.4", "tsutils": "^3.21.0" } }, "@typescript-eslint/types": { - "version": "5.30.6", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.30.6.tgz", - "integrity": "sha512-HdnP8HioL1F7CwVmT4RaaMX57RrfqsOMclZc08wGMiDYJBsLGBM7JwXM4cZJmbWLzIR/pXg1kkrBBVpxTOwfUg==", + "version": "5.42.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.42.0.tgz", + "integrity": "sha512-t4lzO9ZOAUcHY6bXQYRuu+3SSYdD9TS8ooApZft4WARt4/f2Cj/YpvbTe8A4GuhT4bNW72goDMOy7SW71mZwGw==", "dev": true }, "@typescript-eslint/typescript-estree": { - "version": "5.30.6", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.30.6.tgz", - "integrity": "sha512-Z7TgPoeYUm06smfEfYF0RBkpF8csMyVnqQbLYiGgmUSTaSXTP57bt8f0UFXstbGxKIreTwQCujtaH0LY9w9B+A==", + "version": "5.42.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.42.0.tgz", + "integrity": "sha512-2O3vSq794x3kZGtV7i4SCWZWCwjEtkWfVqX4m5fbUBomOsEOyd6OAD1qU2lbvV5S8tgy/luJnOYluNyYVeOTTg==", "dev": true, "requires": { - "@typescript-eslint/types": "5.30.6", - "@typescript-eslint/visitor-keys": "5.30.6", + "@typescript-eslint/types": "5.42.0", + "@typescript-eslint/visitor-keys": "5.42.0", "debug": "^4.3.4", "globby": "^11.1.0", "is-glob": "^4.0.3", @@ -6434,51 +6692,35 @@ } }, "@typescript-eslint/utils": { - "version": "5.30.6", - "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-5.30.6.tgz", - "integrity": "sha512-xFBLc/esUbLOJLk9jKv0E9gD/OH966M40aY9jJ8GiqpSkP2xOV908cokJqqhVd85WoIvHVHYXxSFE4cCSDzVvA==", + "version": "5.42.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-5.42.0.tgz", + "integrity": "sha512-JZ++3+h1vbeG1NUECXQZE3hg0kias9kOtcQr3+JVQ3whnjvKuMyktJAAIj6743OeNPnGBmjj7KEmiDL7qsdnCQ==", "dev": true, "requires": { "@types/json-schema": "^7.0.9", - "@typescript-eslint/scope-manager": "5.30.6", - "@typescript-eslint/types": "5.30.6", - "@typescript-eslint/typescript-estree": "5.30.6", + "@types/semver": "^7.3.12", + "@typescript-eslint/scope-manager": "5.42.0", + "@typescript-eslint/types": "5.42.0", + "@typescript-eslint/typescript-estree": "5.42.0", "eslint-scope": "^5.1.1", - "eslint-utils": "^3.0.0" - }, - "dependencies": { - "eslint-scope": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz", - "integrity": "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==", - "dev": true, - "requires": { - "esrecurse": "^4.3.0", - "estraverse": "^4.1.1" - } - }, - "estraverse": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", - "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", - "dev": true - } + "eslint-utils": "^3.0.0", + "semver": "^7.3.7" } }, "@typescript-eslint/visitor-keys": { - "version": "5.30.6", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.30.6.tgz", - "integrity": "sha512-41OiCjdL2mCaSDi2SvYbzFLlqqlm5v1ZW9Ym55wXKL/Rx6OOB1IbuFGo71Fj6Xy90gJDFTlgOS+vbmtGHPTQQA==", + "version": "5.42.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.42.0.tgz", + "integrity": "sha512-QHbu5Hf/2lOEOwy+IUw0GoSCuAzByTAWWrOTKzTzsotiUnWFpuKnXcAhC9YztAf2EElQ0VvIK+pHJUPkM0q7jg==", "dev": true, "requires": { - "@typescript-eslint/types": "5.30.6", + "@typescript-eslint/types": "5.42.0", "eslint-visitor-keys": "^3.3.0" } }, "acorn": { - "version": "8.8.0", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.8.0.tgz", - "integrity": "sha512-QOxyigPVrpZ2GXT+PFyZTl6TtOFc5egxHIP9IlQ+RbupQuX4RkT/Bee4/kQuC02Xkzg84JcT7oLYtDIQxp+v7w==" + "version": "8.8.1", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.8.1.tgz", + "integrity": "sha512-7zFpHzhnqYKrkYdUjF1HI1bzd0VygEGX8lFk4k5zVMqHEoES+P+7TKI+EvLO9WVMJ8eekdO0aDEK044xTXwPPA==" }, "acorn-jsx": { "version": "5.3.2", @@ -6654,15 +6896,15 @@ } }, "browserslist": { - "version": "4.21.2", - "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.21.2.tgz", - "integrity": "sha512-MonuOgAtUB46uP5CezYbRaYKBNt2LxP0yX+Pmj4LkcDFGkn9Cbpi83d9sCjwQDErXsIJSzY5oKGDbgOlF/LPAA==", + "version": "4.21.4", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.21.4.tgz", + "integrity": "sha512-CBHJJdDmgjl3daYjN5Cp5kbTf1mUhZoS+beLklHIvkOWscs83YAhLlF3Wsh/lciQYAcbBJgTOD44VtG31ZM4Hw==", "dev": true, "requires": { - "caniuse-lite": "^1.0.30001366", - "electron-to-chromium": "^1.4.188", + "caniuse-lite": "^1.0.30001400", + "electron-to-chromium": "^1.4.251", "node-releases": "^2.0.6", - "update-browserslist-db": "^1.0.4" + "update-browserslist-db": "^1.0.9" } }, "bs-logger": { @@ -6689,6 +6931,14 @@ "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==", "dev": true }, + "busboy": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/busboy/-/busboy-1.6.0.tgz", + "integrity": "sha512-8SFQbg/0hQ9xy3UNTB0YEnsNBbWfhf7RtnzpL7TkBiTBRfrQ9Fxcnz7VJsleJpyp6rVLvXiuORqjlHi5q+PYuA==", + "requires": { + "streamsearch": "^1.1.0" + } + }, "callsites": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", @@ -6702,9 +6952,9 @@ "dev": true }, "caniuse-lite": { - "version": "1.0.30001367", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001367.tgz", - "integrity": "sha512-XDgbeOHfifWV3GEES2B8rtsrADx4Jf+juKX2SICJcaUhjYBO3bR96kvEIHa15VU6ohtOhBZuPGGYGbXMRn0NCw==", + "version": "1.0.30001430", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001430.tgz", + "integrity": "sha512-IB1BXTZKPDVPM7cnV4iaKaHxckvdr/3xtctB3f7Hmenx3qYBhGtTZ//7EllK66aKXW98Lx0+7Yr0kxBtIt3tzg==", "dev": true }, "chalk": { @@ -6724,9 +6974,9 @@ "dev": true }, "ci-info": { - "version": "3.3.2", - "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-3.3.2.tgz", - "integrity": "sha512-xmDt/QIAdeZ9+nfdPsaBCpMvHNLFiLdjj59qjqn+6iPe6YmHGQ35sBnQ8uslRBXFmXkiZQOJRjvQeoGppoTjjg==", + "version": "3.5.0", + "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-3.5.0.tgz", + "integrity": "sha512-yH4RezKOGlOhxkmhbeNuC4eYZKAUsEaGtBuBzDDP1eFUKiccDWzBABxBfOx31IDwDIXMTxWuwAxUGModvkbuVw==", "dev": true }, "cjs-module-lexer": { @@ -6736,13 +6986,13 @@ "dev": true }, "cliui": { - "version": "7.0.4", - "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz", - "integrity": "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==", + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz", + "integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==", "dev": true, "requires": { "string-width": "^4.2.0", - "strip-ansi": "^6.0.0", + "strip-ansi": "^6.0.1", "wrap-ansi": "^7.0.0" } }, @@ -6780,13 +7030,10 @@ "dev": true }, "convert-source-map": { - "version": "1.8.0", - "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.8.0.tgz", - "integrity": "sha512-+OQdjP49zViI/6i7nIJpA8rAl4sV/JdPfU9nZs3VqOwGIgizICvuN2ru6fMd+4llL0tar18UYJXfZ/TWtmhUjA==", - "dev": true, - "requires": { - "safe-buffer": "~5.1.1" - } + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.9.0.tgz", + "integrity": "sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A==", + "dev": true }, "cross-spawn": { "version": "7.0.3", @@ -6912,9 +7159,9 @@ } }, "electron-to-chromium": { - "version": "1.4.192", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.192.tgz", - "integrity": "sha512-8nCXyIQY9An88NXAp+PuPy5h3/w5ZY7Iu2lag65Q0XREprcat5F8gKhoHsBUnQcFuCRnmevpR8yEBYRU3d2HDw==", + "version": "1.4.284", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.284.tgz", + "integrity": "sha512-M8WEXFuKXMYMVr45fo8mq0wUrrJHheiKZf6BArTKk9ZBYCKJEOU5H8cdWgDT+qCVZf7Na4lVUaZsA+h6uA9+PA==", "dev": true }, "emittery": { @@ -6930,9 +7177,9 @@ "dev": true }, "entities": { - "version": "4.3.1", - "resolved": "https://registry.npmjs.org/entities/-/entities-4.3.1.tgz", - "integrity": "sha512-o4q/dYJlmyjP2zfnaWDUC6A3BQFmVTX+tZPezK7k0GLSU9QYCauscf5Y+qcEPzKL+EixVouYDgLQK5H9GrLpkg==" + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/entities/-/entities-4.4.0.tgz", + "integrity": "sha512-oYp7156SP8LkeGD0GF85ad1X9Ai79WtRsZ2gxJqtBuzH+98YUV6jkHEKlZkMbcrjJjIVJNIDP/3WL9wQkoPbWA==" }, "error-ex": { "version": "1.3.2", @@ -6944,170 +7191,171 @@ } }, "esbuild": { - "version": "0.14.49", - "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.14.49.tgz", - "integrity": "sha512-/TlVHhOaq7Yz8N1OJrjqM3Auzo5wjvHFLk+T8pIue+fhnhIMpfAzsG6PLVMbFveVxqD2WOp3QHei+52IMUNmCw==", + "version": "0.14.54", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.14.54.tgz", + "integrity": "sha512-Cy9llcy8DvET5uznocPyqL3BFRrFXSVqbgpMJ9Wz8oVjZlh/zUSNbPRbov0VX7VxN2JH1Oa0uNxZ7eLRb62pJA==", "dev": true, "requires": { - "esbuild-android-64": "0.14.49", - "esbuild-android-arm64": "0.14.49", - "esbuild-darwin-64": "0.14.49", - "esbuild-darwin-arm64": "0.14.49", - "esbuild-freebsd-64": "0.14.49", - "esbuild-freebsd-arm64": "0.14.49", - "esbuild-linux-32": "0.14.49", - "esbuild-linux-64": "0.14.49", - "esbuild-linux-arm": "0.14.49", - "esbuild-linux-arm64": "0.14.49", - "esbuild-linux-mips64le": "0.14.49", - "esbuild-linux-ppc64le": "0.14.49", - "esbuild-linux-riscv64": "0.14.49", - "esbuild-linux-s390x": "0.14.49", - "esbuild-netbsd-64": "0.14.49", - "esbuild-openbsd-64": "0.14.49", - "esbuild-sunos-64": "0.14.49", - "esbuild-windows-32": "0.14.49", - "esbuild-windows-64": "0.14.49", - "esbuild-windows-arm64": "0.14.49" + "@esbuild/linux-loong64": "0.14.54", + "esbuild-android-64": "0.14.54", + "esbuild-android-arm64": "0.14.54", + "esbuild-darwin-64": "0.14.54", + "esbuild-darwin-arm64": "0.14.54", + "esbuild-freebsd-64": "0.14.54", + "esbuild-freebsd-arm64": "0.14.54", + "esbuild-linux-32": "0.14.54", + "esbuild-linux-64": "0.14.54", + "esbuild-linux-arm": "0.14.54", + "esbuild-linux-arm64": "0.14.54", + "esbuild-linux-mips64le": "0.14.54", + "esbuild-linux-ppc64le": "0.14.54", + "esbuild-linux-riscv64": "0.14.54", + "esbuild-linux-s390x": "0.14.54", + "esbuild-netbsd-64": "0.14.54", + "esbuild-openbsd-64": "0.14.54", + "esbuild-sunos-64": "0.14.54", + "esbuild-windows-32": "0.14.54", + "esbuild-windows-64": "0.14.54", + "esbuild-windows-arm64": "0.14.54" } }, "esbuild-android-64": { - "version": "0.14.49", - "resolved": "https://registry.npmjs.org/esbuild-android-64/-/esbuild-android-64-0.14.49.tgz", - "integrity": "sha512-vYsdOTD+yi+kquhBiFWl3tyxnj2qZJsl4tAqwhT90ktUdnyTizgle7TjNx6Ar1bN7wcwWqZ9QInfdk2WVagSww==", + "version": "0.14.54", + "resolved": "https://registry.npmjs.org/esbuild-android-64/-/esbuild-android-64-0.14.54.tgz", + "integrity": "sha512-Tz2++Aqqz0rJ7kYBfz+iqyE3QMycD4vk7LBRyWaAVFgFtQ/O8EJOnVmTOiDWYZ/uYzB4kvP+bqejYdVKzE5lAQ==", "dev": true, "optional": true }, "esbuild-android-arm64": { - "version": "0.14.49", - "resolved": "https://registry.npmjs.org/esbuild-android-arm64/-/esbuild-android-arm64-0.14.49.tgz", - "integrity": "sha512-g2HGr/hjOXCgSsvQZ1nK4nW/ei8JUx04Li74qub9qWrStlysaVmadRyTVuW32FGIpLQyc5sUjjZopj49eGGM2g==", + "version": "0.14.54", + "resolved": "https://registry.npmjs.org/esbuild-android-arm64/-/esbuild-android-arm64-0.14.54.tgz", + "integrity": "sha512-F9E+/QDi9sSkLaClO8SOV6etqPd+5DgJje1F9lOWoNncDdOBL2YF59IhsWATSt0TLZbYCf3pNlTHvVV5VfHdvg==", "dev": true, "optional": true }, "esbuild-darwin-64": { - "version": "0.14.49", - "resolved": "https://registry.npmjs.org/esbuild-darwin-64/-/esbuild-darwin-64-0.14.49.tgz", - "integrity": "sha512-3rvqnBCtX9ywso5fCHixt2GBCUsogNp9DjGmvbBohh31Ces34BVzFltMSxJpacNki96+WIcX5s/vum+ckXiLYg==", + "version": "0.14.54", + "resolved": "https://registry.npmjs.org/esbuild-darwin-64/-/esbuild-darwin-64-0.14.54.tgz", + "integrity": "sha512-jtdKWV3nBviOd5v4hOpkVmpxsBy90CGzebpbO9beiqUYVMBtSc0AL9zGftFuBon7PNDcdvNCEuQqw2x0wP9yug==", "dev": true, "optional": true }, "esbuild-darwin-arm64": { - "version": "0.14.49", - "resolved": "https://registry.npmjs.org/esbuild-darwin-arm64/-/esbuild-darwin-arm64-0.14.49.tgz", - "integrity": "sha512-XMaqDxO846srnGlUSJnwbijV29MTKUATmOLyQSfswbK/2X5Uv28M9tTLUJcKKxzoo9lnkYPsx2o8EJcTYwCs/A==", + "version": "0.14.54", + "resolved": "https://registry.npmjs.org/esbuild-darwin-arm64/-/esbuild-darwin-arm64-0.14.54.tgz", + "integrity": "sha512-OPafJHD2oUPyvJMrsCvDGkRrVCar5aVyHfWGQzY1dWnzErjrDuSETxwA2HSsyg2jORLY8yBfzc1MIpUkXlctmw==", "dev": true, "optional": true }, "esbuild-freebsd-64": { - "version": "0.14.49", - "resolved": "https://registry.npmjs.org/esbuild-freebsd-64/-/esbuild-freebsd-64-0.14.49.tgz", - "integrity": "sha512-NJ5Q6AjV879mOHFri+5lZLTp5XsO2hQ+KSJYLbfY9DgCu8s6/Zl2prWXVANYTeCDLlrIlNNYw8y34xqyLDKOmQ==", + "version": "0.14.54", + "resolved": "https://registry.npmjs.org/esbuild-freebsd-64/-/esbuild-freebsd-64-0.14.54.tgz", + "integrity": "sha512-OKwd4gmwHqOTp4mOGZKe/XUlbDJ4Q9TjX0hMPIDBUWWu/kwhBAudJdBoxnjNf9ocIB6GN6CPowYpR/hRCbSYAg==", "dev": true, "optional": true }, "esbuild-freebsd-arm64": { - "version": "0.14.49", - "resolved": "https://registry.npmjs.org/esbuild-freebsd-arm64/-/esbuild-freebsd-arm64-0.14.49.tgz", - "integrity": "sha512-lFLtgXnAc3eXYqj5koPlBZvEbBSOSUbWO3gyY/0+4lBdRqELyz4bAuamHvmvHW5swJYL7kngzIZw6kdu25KGOA==", + "version": "0.14.54", + "resolved": "https://registry.npmjs.org/esbuild-freebsd-arm64/-/esbuild-freebsd-arm64-0.14.54.tgz", + "integrity": "sha512-sFwueGr7OvIFiQT6WeG0jRLjkjdqWWSrfbVwZp8iMP+8UHEHRBvlaxL6IuKNDwAozNUmbb8nIMXa7oAOARGs1Q==", "dev": true, "optional": true }, "esbuild-linux-32": { - "version": "0.14.49", - "resolved": "https://registry.npmjs.org/esbuild-linux-32/-/esbuild-linux-32-0.14.49.tgz", - "integrity": "sha512-zTTH4gr2Kb8u4QcOpTDVn7Z8q7QEIvFl/+vHrI3cF6XOJS7iEI1FWslTo3uofB2+mn6sIJEQD9PrNZKoAAMDiA==", + "version": "0.14.54", + "resolved": "https://registry.npmjs.org/esbuild-linux-32/-/esbuild-linux-32-0.14.54.tgz", + "integrity": "sha512-1ZuY+JDI//WmklKlBgJnglpUL1owm2OX+8E1syCD6UAxcMM/XoWd76OHSjl/0MR0LisSAXDqgjT3uJqT67O3qw==", "dev": true, "optional": true }, "esbuild-linux-64": { - "version": "0.14.49", - "resolved": "https://registry.npmjs.org/esbuild-linux-64/-/esbuild-linux-64-0.14.49.tgz", - "integrity": "sha512-hYmzRIDzFfLrB5c1SknkxzM8LdEUOusp6M2TnuQZJLRtxTgyPnZZVtyMeCLki0wKgYPXkFsAVhi8vzo2mBNeTg==", + "version": "0.14.54", + "resolved": "https://registry.npmjs.org/esbuild-linux-64/-/esbuild-linux-64-0.14.54.tgz", + "integrity": "sha512-EgjAgH5HwTbtNsTqQOXWApBaPVdDn7XcK+/PtJwZLT1UmpLoznPd8c5CxqsH2dQK3j05YsB3L17T8vE7cp4cCg==", "dev": true, "optional": true }, "esbuild-linux-arm": { - "version": "0.14.49", - "resolved": "https://registry.npmjs.org/esbuild-linux-arm/-/esbuild-linux-arm-0.14.49.tgz", - "integrity": "sha512-iE3e+ZVv1Qz1Sy0gifIsarJMQ89Rpm9mtLSRtG3AH0FPgAzQ5Z5oU6vYzhc/3gSPi2UxdCOfRhw2onXuFw/0lg==", + "version": "0.14.54", + "resolved": "https://registry.npmjs.org/esbuild-linux-arm/-/esbuild-linux-arm-0.14.54.tgz", + "integrity": "sha512-qqz/SjemQhVMTnvcLGoLOdFpCYbz4v4fUo+TfsWG+1aOu70/80RV6bgNpR2JCrppV2moUQkww+6bWxXRL9YMGw==", "dev": true, "optional": true }, "esbuild-linux-arm64": { - "version": "0.14.49", - "resolved": "https://registry.npmjs.org/esbuild-linux-arm64/-/esbuild-linux-arm64-0.14.49.tgz", - "integrity": "sha512-KLQ+WpeuY+7bxukxLz5VgkAAVQxUv67Ft4DmHIPIW+2w3ObBPQhqNoeQUHxopoW/aiOn3m99NSmSV+bs4BSsdA==", + "version": "0.14.54", + "resolved": "https://registry.npmjs.org/esbuild-linux-arm64/-/esbuild-linux-arm64-0.14.54.tgz", + "integrity": "sha512-WL71L+0Rwv+Gv/HTmxTEmpv0UgmxYa5ftZILVi2QmZBgX3q7+tDeOQNqGtdXSdsL8TQi1vIaVFHUPDe0O0kdig==", "dev": true, "optional": true }, "esbuild-linux-mips64le": { - "version": "0.14.49", - "resolved": "https://registry.npmjs.org/esbuild-linux-mips64le/-/esbuild-linux-mips64le-0.14.49.tgz", - "integrity": "sha512-n+rGODfm8RSum5pFIqFQVQpYBw+AztL8s6o9kfx7tjfK0yIGF6tm5HlG6aRjodiiKkH2xAiIM+U4xtQVZYU4rA==", + "version": "0.14.54", + "resolved": "https://registry.npmjs.org/esbuild-linux-mips64le/-/esbuild-linux-mips64le-0.14.54.tgz", + "integrity": "sha512-qTHGQB8D1etd0u1+sB6p0ikLKRVuCWhYQhAHRPkO+OF3I/iSlTKNNS0Lh2Oc0g0UFGguaFZZiPJdJey3AGpAlw==", "dev": true, "optional": true }, "esbuild-linux-ppc64le": { - "version": "0.14.49", - "resolved": "https://registry.npmjs.org/esbuild-linux-ppc64le/-/esbuild-linux-ppc64le-0.14.49.tgz", - "integrity": "sha512-WP9zR4HX6iCBmMFH+XHHng2LmdoIeUmBpL4aL2TR8ruzXyT4dWrJ5BSbT8iNo6THN8lod6GOmYDLq/dgZLalGw==", + "version": "0.14.54", + "resolved": "https://registry.npmjs.org/esbuild-linux-ppc64le/-/esbuild-linux-ppc64le-0.14.54.tgz", + "integrity": "sha512-j3OMlzHiqwZBDPRCDFKcx595XVfOfOnv68Ax3U4UKZ3MTYQB5Yz3X1mn5GnodEVYzhtZgxEBidLWeIs8FDSfrQ==", "dev": true, "optional": true }, "esbuild-linux-riscv64": { - "version": "0.14.49", - "resolved": "https://registry.npmjs.org/esbuild-linux-riscv64/-/esbuild-linux-riscv64-0.14.49.tgz", - "integrity": "sha512-h66ORBz+Dg+1KgLvzTVQEA1LX4XBd1SK0Fgbhhw4akpG/YkN8pS6OzYI/7SGENiN6ao5hETRDSkVcvU9NRtkMQ==", + "version": "0.14.54", + "resolved": "https://registry.npmjs.org/esbuild-linux-riscv64/-/esbuild-linux-riscv64-0.14.54.tgz", + "integrity": "sha512-y7Vt7Wl9dkOGZjxQZnDAqqn+XOqFD7IMWiewY5SPlNlzMX39ocPQlOaoxvT4FllA5viyV26/QzHtvTjVNOxHZg==", "dev": true, "optional": true }, "esbuild-linux-s390x": { - "version": "0.14.49", - "resolved": "https://registry.npmjs.org/esbuild-linux-s390x/-/esbuild-linux-s390x-0.14.49.tgz", - "integrity": "sha512-DhrUoFVWD+XmKO1y7e4kNCqQHPs6twz6VV6Uezl/XHYGzM60rBewBF5jlZjG0nCk5W/Xy6y1xWeopkrhFFM0sQ==", + "version": "0.14.54", + "resolved": "https://registry.npmjs.org/esbuild-linux-s390x/-/esbuild-linux-s390x-0.14.54.tgz", + "integrity": "sha512-zaHpW9dziAsi7lRcyV4r8dhfG1qBidQWUXweUjnw+lliChJqQr+6XD71K41oEIC3Mx1KStovEmlzm+MkGZHnHA==", "dev": true, "optional": true }, "esbuild-netbsd-64": { - "version": "0.14.49", - "resolved": "https://registry.npmjs.org/esbuild-netbsd-64/-/esbuild-netbsd-64-0.14.49.tgz", - "integrity": "sha512-BXaUwFOfCy2T+hABtiPUIpWjAeWK9P8O41gR4Pg73hpzoygVGnj0nI3YK4SJhe52ELgtdgWP/ckIkbn2XaTxjQ==", + "version": "0.14.54", + "resolved": "https://registry.npmjs.org/esbuild-netbsd-64/-/esbuild-netbsd-64-0.14.54.tgz", + "integrity": "sha512-PR01lmIMnfJTgeU9VJTDY9ZerDWVFIUzAtJuDHwwceppW7cQWjBBqP48NdeRtoP04/AtO9a7w3viI+PIDr6d+w==", "dev": true, "optional": true }, "esbuild-openbsd-64": { - "version": "0.14.49", - "resolved": "https://registry.npmjs.org/esbuild-openbsd-64/-/esbuild-openbsd-64-0.14.49.tgz", - "integrity": "sha512-lP06UQeLDGmVPw9Rg437Btu6J9/BmyhdoefnQ4gDEJTtJvKtQaUcOQrhjTq455ouZN4EHFH1h28WOJVANK41kA==", + "version": "0.14.54", + "resolved": "https://registry.npmjs.org/esbuild-openbsd-64/-/esbuild-openbsd-64-0.14.54.tgz", + "integrity": "sha512-Qyk7ikT2o7Wu76UsvvDS5q0amJvmRzDyVlL0qf5VLsLchjCa1+IAvd8kTBgUxD7VBUUVgItLkk609ZHUc1oCaw==", "dev": true, "optional": true }, "esbuild-sunos-64": { - "version": "0.14.49", - "resolved": "https://registry.npmjs.org/esbuild-sunos-64/-/esbuild-sunos-64-0.14.49.tgz", - "integrity": "sha512-4c8Zowp+V3zIWje329BeLbGh6XI9c/rqARNaj5yPHdC61pHI9UNdDxT3rePPJeWcEZVKjkiAS6AP6kiITp7FSw==", + "version": "0.14.54", + "resolved": "https://registry.npmjs.org/esbuild-sunos-64/-/esbuild-sunos-64-0.14.54.tgz", + "integrity": "sha512-28GZ24KmMSeKi5ueWzMcco6EBHStL3B6ubM7M51RmPwXQGLe0teBGJocmWhgwccA1GeFXqxzILIxXpHbl9Q/Kw==", "dev": true, "optional": true }, "esbuild-windows-32": { - "version": "0.14.49", - "resolved": "https://registry.npmjs.org/esbuild-windows-32/-/esbuild-windows-32-0.14.49.tgz", - "integrity": "sha512-q7Rb+J9yHTeKr9QTPDYkqfkEj8/kcKz9lOabDuvEXpXuIcosWCJgo5Z7h/L4r7rbtTH4a8U2FGKb6s1eeOHmJA==", + "version": "0.14.54", + "resolved": "https://registry.npmjs.org/esbuild-windows-32/-/esbuild-windows-32-0.14.54.tgz", + "integrity": "sha512-T+rdZW19ql9MjS7pixmZYVObd9G7kcaZo+sETqNH4RCkuuYSuv9AGHUVnPoP9hhuE1WM1ZimHz1CIBHBboLU7w==", "dev": true, "optional": true }, "esbuild-windows-64": { - "version": "0.14.49", - "resolved": "https://registry.npmjs.org/esbuild-windows-64/-/esbuild-windows-64-0.14.49.tgz", - "integrity": "sha512-+Cme7Ongv0UIUTniPqfTX6mJ8Deo7VXw9xN0yJEN1lQMHDppTNmKwAM3oGbD/Vqff+07K2gN0WfNkMohmG+dVw==", + "version": "0.14.54", + "resolved": "https://registry.npmjs.org/esbuild-windows-64/-/esbuild-windows-64-0.14.54.tgz", + "integrity": "sha512-AoHTRBUuYwXtZhjXZbA1pGfTo8cJo3vZIcWGLiUcTNgHpJJMC1rVA44ZereBHMJtotyN71S8Qw0npiCIkW96cQ==", "dev": true, "optional": true }, "esbuild-windows-arm64": { - "version": "0.14.49", - "resolved": "https://registry.npmjs.org/esbuild-windows-arm64/-/esbuild-windows-arm64-0.14.49.tgz", - "integrity": "sha512-v+HYNAXzuANrCbbLFJ5nmO3m5y2PGZWLe3uloAkLt87aXiO2mZr3BTmacZdjwNkNEHuH3bNtN8cak+mzVjVPfA==", + "version": "0.14.54", + "resolved": "https://registry.npmjs.org/esbuild-windows-arm64/-/esbuild-windows-arm64-0.14.54.tgz", + "integrity": "sha512-M0kuUvXhot1zOISQGXwWn6YtS+Y/1RT9WrVIOywZnJHo3jCDyewAc79aKNQWFCQm+xNHVTq9h8dZKvygoXQQRg==", "dev": true, "optional": true }, @@ -7124,13 +7372,15 @@ "dev": true }, "eslint": { - "version": "8.19.0", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.19.0.tgz", - "integrity": "sha512-SXOPj3x9VKvPe81TjjUJCYlV4oJjQw68Uek+AM0X4p+33dj2HY5bpTZOgnQHcG2eAm1mtCU9uNMnJi7exU/kYw==", + "version": "8.26.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.26.0.tgz", + "integrity": "sha512-kzJkpaw1Bfwheq4VXUezFriD1GxszX6dUekM7Z3aC2o4hju+tsR/XyTC3RcoSD7jmy9VkPU3+N6YjVU2e96Oyg==", "dev": true, "requires": { - "@eslint/eslintrc": "^1.3.0", - "@humanwhocodes/config-array": "^0.9.2", + "@eslint/eslintrc": "^1.3.3", + "@humanwhocodes/config-array": "^0.11.6", + "@humanwhocodes/module-importer": "^1.0.1", + "@nodelib/fs.walk": "^1.2.8", "ajv": "^6.10.0", "chalk": "^4.0.0", "cross-spawn": "^7.0.2", @@ -7140,18 +7390,21 @@ "eslint-scope": "^7.1.1", "eslint-utils": "^3.0.0", "eslint-visitor-keys": "^3.3.0", - "espree": "^9.3.2", + "espree": "^9.4.0", "esquery": "^1.4.0", "esutils": "^2.0.2", "fast-deep-equal": "^3.1.3", "file-entry-cache": "^6.0.1", - "functional-red-black-tree": "^1.0.1", - "glob-parent": "^6.0.1", + "find-up": "^5.0.0", + "glob-parent": "^6.0.2", "globals": "^13.15.0", + "grapheme-splitter": "^1.0.4", "ignore": "^5.2.0", "import-fresh": "^3.0.0", "imurmurhash": "^0.1.4", "is-glob": "^4.0.0", + "is-path-inside": "^3.0.3", + "js-sdsl": "^4.1.4", "js-yaml": "^4.1.0", "json-stable-stringify-without-jsonify": "^1.0.1", "levn": "^0.4.1", @@ -7162,28 +7415,45 @@ "regexpp": "^3.2.0", "strip-ansi": "^6.0.1", "strip-json-comments": "^3.1.0", - "text-table": "^0.2.0", - "v8-compile-cache": "^2.0.3" + "text-table": "^0.2.0" + }, + "dependencies": { + "eslint-scope": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.1.1.tgz", + "integrity": "sha512-QKQM/UXpIiHcLqJ5AOyIW7XZmzjkzQXYE54n1++wb0u9V/abW3l9uQnxX8Z5Xd18xyKIMTUAyQ0k1e8pz6LUrw==", + "dev": true, + "requires": { + "esrecurse": "^4.3.0", + "estraverse": "^5.2.0" + } + }, + "estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "dev": true + } } }, "eslint-plugin-tsdoc": { - "version": "0.2.16", - "resolved": "https://registry.npmjs.org/eslint-plugin-tsdoc/-/eslint-plugin-tsdoc-0.2.16.tgz", - "integrity": "sha512-F/RWMnyDQuGlg82vQEFHQtGyWi7++XJKdYNn0ulIbyMOFqYIjoJOUdE6olORxgwgLkpJxsCJpJbTHgxJ/ggfXw==", + "version": "0.2.17", + "resolved": "https://registry.npmjs.org/eslint-plugin-tsdoc/-/eslint-plugin-tsdoc-0.2.17.tgz", + "integrity": "sha512-xRmVi7Zx44lOBuYqG8vzTXuL6IdGOeF9nHX17bjJ8+VE6fsxpdGem0/SBTmAwgYMKYB1WBkqRJVQ+n8GK041pA==", "dev": true, "requires": { - "@microsoft/tsdoc": "0.14.1", - "@microsoft/tsdoc-config": "0.16.1" + "@microsoft/tsdoc": "0.14.2", + "@microsoft/tsdoc-config": "0.16.2" } }, "eslint-scope": { - "version": "7.1.1", - "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.1.1.tgz", - "integrity": "sha512-QKQM/UXpIiHcLqJ5AOyIW7XZmzjkzQXYE54n1++wb0u9V/abW3l9uQnxX8Z5Xd18xyKIMTUAyQ0k1e8pz6LUrw==", + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz", + "integrity": "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==", "dev": true, "requires": { "esrecurse": "^4.3.0", - "estraverse": "^5.2.0" + "estraverse": "^4.1.1" } }, "eslint-utils": { @@ -7210,12 +7480,12 @@ "dev": true }, "espree": { - "version": "9.3.2", - "resolved": "https://registry.npmjs.org/espree/-/espree-9.3.2.tgz", - "integrity": "sha512-D211tC7ZwouTIuY5x9XnS0E9sWNChB7IYKX/Xp5eQj3nFXhqmiUDB9q27y76oFl8jTg3pXcQx/bpxMfs3CIZbA==", + "version": "9.4.1", + "resolved": "https://registry.npmjs.org/espree/-/espree-9.4.1.tgz", + "integrity": "sha512-XwctdmTO6SIvCzd9810yyNzIrOrqNYV9Koizx4C/mRhf9uq0o4yHoCEU/670pOxOL/MSraektvSAji79kX90Vg==", "dev": true, "requires": { - "acorn": "^8.7.1", + "acorn": "^8.8.0", "acorn-jsx": "^5.3.2", "eslint-visitor-keys": "^3.3.0" } @@ -7233,6 +7503,14 @@ "dev": true, "requires": { "estraverse": "^5.1.0" + }, + "dependencies": { + "estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "dev": true + } } }, "esrecurse": { @@ -7242,12 +7520,20 @@ "dev": true, "requires": { "estraverse": "^5.2.0" + }, + "dependencies": { + "estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "dev": true + } } }, "estraverse": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", - "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", + "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", "dev": true }, "esutils": { @@ -7299,9 +7585,9 @@ "dev": true }, "fast-glob": { - "version": "3.2.11", - "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.11.tgz", - "integrity": "sha512-xrO3+1bxSo3ZVHAnqzyuewYT6aMFHRAd4Kcs92MAonjwQZLsK9d0SF1IyQ3k5PoirxTW0Oe/RqFgMQ6TcNE5Ew==", + "version": "3.2.12", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.12.tgz", + "integrity": "sha512-DVj4CQIYYow0BlaelwK1pHl5n5cRSJfM60UA0zK891sVInoPri2Ekj7+e1CT3/3qxXenpI+nBBmQAcJPJgaj4w==", "dev": true, "requires": { "@nodelib/fs.stat": "^2.0.2", @@ -7344,9 +7630,9 @@ } }, "fb-watchman": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/fb-watchman/-/fb-watchman-2.0.1.tgz", - "integrity": "sha512-DkPJKQeY6kKwmuMretBhr7G6Vodr7bFwDYTXIkfG1gjvNpaxBTQV3PbXg6bR1c1UP4jPOX0jHUbbHANL9vRjVg==", + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/fb-watchman/-/fb-watchman-2.0.2.tgz", + "integrity": "sha512-p5161BqbuCaSnB8jIbzQHOlpgsPmK5rJVDfDKO91Axs5NC1uu3HRQm6wt9cd9/+GtQQIO53JdGXXoyDpTAsgYA==", "dev": true, "requires": { "bser": "2.1.1" @@ -7371,12 +7657,12 @@ } }, "find-up": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", - "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", + "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", "dev": true, "requires": { - "locate-path": "^5.0.0", + "locate-path": "^6.0.0", "path-exists": "^4.0.0" } }, @@ -7391,9 +7677,9 @@ } }, "flatted": { - "version": "3.2.6", - "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.2.6.tgz", - "integrity": "sha512-0sQoMh9s0BYsm+12Huy/rkKxVu4R1+r96YX5cG44rHV0pQ6iC3Q+mkoMFaGWObMFYQxCVT+ssG1ksneA2MI9KQ==", + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.2.7.tgz", + "integrity": "sha512-5nqDSxl8nn5BSNxyR3n4I6eDmbolI6WT+QqR547RwxQapgjQBmtktdP+HTBb/a/zLsbzERTONyUB5pefh5TtjQ==", "dev": true }, "fs.realpath": { @@ -7415,12 +7701,6 @@ "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==", "dev": true }, - "functional-red-black-tree": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz", - "integrity": "sha512-dsKNQNdj6xA3T+QlADDA7mOSlX0qiMINjn0cgr+eGHGsbSHzTabcIogz2+p/iqP1Xs6EP/sS2SbqH+brGTbq0g==", - "dev": true - }, "gensync": { "version": "1.0.0-beta.2", "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", @@ -7488,9 +7768,9 @@ } }, "globals": { - "version": "13.16.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-13.16.0.tgz", - "integrity": "sha512-A1lrQfpNF+McdPOnnFqY3kSN0AFTy485bTi1bkLk4mVPODIUEcSfhHgRqA+QdXPksrSTTztYXx37NFV+GpGk3Q==", + "version": "13.17.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-13.17.0.tgz", + "integrity": "sha512-1C+6nQRb1GwGMKm2dH/E7enFAMxGTmGI7/dEdhy/DNelv85w9B72t3uc5frtMNXIbzrarJJ/lTCjcaZwbLJmyw==", "dev": true, "requires": { "type-fest": "^0.20.2" @@ -7516,6 +7796,12 @@ "integrity": "sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA==", "dev": true }, + "grapheme-splitter": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/grapheme-splitter/-/grapheme-splitter-1.0.4.tgz", + "integrity": "sha512-bzh50DW9kTPM00T8y4o8vQg89Di9oLJVLW/KaOGIXJWP/iqCN6WKYkbNOF04vFLJhwcpYUh9ydh/+5vpOqV4YQ==", + "dev": true + }, "has": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", @@ -7609,9 +7895,9 @@ "dev": true }, "is-core-module": { - "version": "2.9.0", - "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.9.0.tgz", - "integrity": "sha512-+5FPy5PnwmO3lvfMb0AsoPaBG+5KHUI0wYFXOtYPnVVVspTFUuMZNfNaNVRt3FZadstu2c8x23vykRW/NBoU6A==", + "version": "2.11.0", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.11.0.tgz", + "integrity": "sha512-RRjxlvLDkD1YJwDbroBHMb+cukurkDWNyHx7D3oNB5x9rb5ogcksMC5wHCadcXoo67gVr/+3GFySh3134zi6rw==", "dev": true, "requires": { "has": "^1.0.3" @@ -7650,6 +7936,12 @@ "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", "dev": true }, + "is-path-inside": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-3.0.3.tgz", + "integrity": "sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==", + "dev": true + }, "is-stream": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", @@ -7669,9 +7961,9 @@ "dev": true }, "istanbul-lib-instrument": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-5.2.0.tgz", - "integrity": "sha512-6Lthe1hqXHBNsqvgDzGO6l03XNeu3CrG4RqQ1KM9+l5+jNGpEJfIELx1NS3SEHmJQA8np/u+E4EPRKRiu6m19A==", + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-5.2.1.tgz", + "integrity": "sha512-pzqtp31nLv/XFOzXGuvhCb8qhjmTVo5vjVk19XE4CRlSWz0KoeJ3bw9XsA7nOp9YBf4qHjwBxkDzKcME/J29Yg==", "dev": true, "requires": { "@babel/core": "^7.12.3", @@ -7987,6 +8279,19 @@ "resolve": "^1.20.0", "resolve.exports": "^1.1.0", "slash": "^3.0.0" + }, + "dependencies": { + "resolve": { + "version": "1.22.1", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.1.tgz", + "integrity": "sha512-nBpuuYuY5jFsli/JIs1oldw6fOQCBioohqWZg/2hiaOybXOft4lonv85uDOKXdf8rhyK159cxU5cDcK/NKk8zw==", + "dev": true, + "requires": { + "is-core-module": "^2.9.0", + "path-parse": "^1.0.7", + "supports-preserve-symlinks-flag": "^1.0.0" + } + } } }, "jest-resolve-dependencies": { @@ -8193,6 +8498,12 @@ "integrity": "sha512-8wb9Yw966OSxApiCt0K3yNJL8pnNeIv+OEq2YMidz4FKP6nonSRoOXc80iXY4JaN2FC11B9qsNmDsm+ZOfMROA==", "dev": true }, + "js-sdsl": { + "version": "4.1.5", + "resolved": "https://registry.npmjs.org/js-sdsl/-/js-sdsl-4.1.5.tgz", + "integrity": "sha512-08bOAKweV2NUC1wqTtf3qZlnpOX/R2DU9ikpjOHs0H+ibQv3zpncVQg6um4uYtRtrwIX8M4Nh3ytK4HGlYAq7Q==", + "dev": true + }, "js-tokens": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", @@ -8267,9 +8578,9 @@ "dev": true }, "linkedom": { - "version": "0.14.12", - "resolved": "https://registry.npmjs.org/linkedom/-/linkedom-0.14.12.tgz", - "integrity": "sha512-8uw8LZifCwyWeVWr80T79sQTMmNXt4Da7oN5yH5gTXRqQM+TuZWJyBqRMcIp32zx/f8anHNHyil9Avw9y76ziQ==", + "version": "0.14.19", + "resolved": "https://registry.npmjs.org/linkedom/-/linkedom-0.14.19.tgz", + "integrity": "sha512-sFNkQZlKBWpEaAcbsDIghTLE0hHbyvS6dZuM7IH+KTM09GaQ772PtDZAuFlN0oFgyAjUj8XS9FpoWSLmBjl8MA==", "requires": { "css-select": "^5.1.0", "cssom": "^0.5.0", @@ -8286,12 +8597,12 @@ } }, "locate-path": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", - "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", + "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", "dev": true, "requires": { - "p-locate": "^4.1.0" + "p-locate": "^5.0.0" } }, "lodash.memoize": { @@ -8396,6 +8707,12 @@ "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", "dev": true }, + "natural-compare-lite": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/natural-compare-lite/-/natural-compare-lite-1.4.0.tgz", + "integrity": "sha512-Tj+HTDSJJKaZnfiuw+iaF9skdPpTo2GtEly5JHnWV/hfv2Qj/9RKsGISQtLh2ox3l5EAGw487hnBee0sIJ6v2g==", + "dev": true + }, "node-int64": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/node-int64/-/node-int64-0.4.0.tgz", @@ -8473,23 +8790,12 @@ } }, "p-locate": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", - "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", + "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", "dev": true, "requires": { - "p-limit": "^2.2.0" - }, - "dependencies": { - "p-limit": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", - "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", - "dev": true, - "requires": { - "p-try": "^2.0.0" - } - } + "p-limit": "^3.0.2" } }, "p-try": { @@ -8574,6 +8880,45 @@ "dev": true, "requires": { "find-up": "^4.0.0" + }, + "dependencies": { + "find-up": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", + "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", + "dev": true, + "requires": { + "locate-path": "^5.0.0", + "path-exists": "^4.0.0" + } + }, + "locate-path": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", + "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", + "dev": true, + "requires": { + "p-locate": "^4.1.0" + } + }, + "p-limit": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", + "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", + "dev": true, + "requires": { + "p-try": "^2.0.0" + } + }, + "p-locate": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", + "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", + "dev": true, + "requires": { + "p-limit": "^2.2.0" + } + } } }, "prelude-ls": { @@ -8643,14 +8988,13 @@ "dev": true }, "resolve": { - "version": "1.22.1", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.1.tgz", - "integrity": "sha512-nBpuuYuY5jFsli/JIs1oldw6fOQCBioohqWZg/2hiaOybXOft4lonv85uDOKXdf8rhyK159cxU5cDcK/NKk8zw==", + "version": "1.19.0", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.19.0.tgz", + "integrity": "sha512-rArEXAgsBG4UgRGcynxWIWKFvh/XZCcS8UJdHhwy91zwAvCZIbcs+vAbflgBnNjYMs/i/i+/Ux6IZhML1yPvxg==", "dev": true, "requires": { - "is-core-module": "^2.9.0", - "path-parse": "^1.0.7", - "supports-preserve-symlinks-flag": "^1.0.0" + "is-core-module": "^2.1.0", + "path-parse": "^1.0.6" } }, "resolve-cwd": { @@ -8722,16 +9066,10 @@ "queue-microtask": "^1.2.2" } }, - "safe-buffer": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", - "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", - "dev": true - }, "semver": { - "version": "7.3.7", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.7.tgz", - "integrity": "sha512-QlYTucUYOews+WeEujDoEGziz4K6c47V/Bd+LjSSYcA94p+DmINdf7ncaUinThfvZyu13lN9OY1XDxt8C0Tw0g==", + "version": "7.3.8", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.8.tgz", + "integrity": "sha512-NB1ctGL5rlHrPJtFDVIVzTyQylMLu9N9VICA6HSFJo8MCGVTMW6gfpicwKmmK/dAjTOrqu5l63JJOpDSrAis3A==", "dev": true, "requires": { "lru-cache": "^6.0.0" @@ -8809,6 +9147,11 @@ } } }, + "streamsearch": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/streamsearch/-/streamsearch-1.1.0.tgz", + "integrity": "sha512-Mcc5wHehp9aXz1ax6bZUyY5afg9u2rv5cqQI3mRrYkGC8rW2hM02jWuwjtL++LS5qinSyhj2QfLyNsuc+VsExg==" + }, "string-length": { "version": "4.0.2", "resolved": "https://registry.npmjs.org/string-length/-/string-length-4.0.2.tgz", @@ -8867,9 +9210,9 @@ } }, "supports-hyperlinks": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/supports-hyperlinks/-/supports-hyperlinks-2.2.0.tgz", - "integrity": "sha512-6sXEzV5+I5j8Bmq9/vUphGRM/RJNT9SCURJLjwfOg51heRtguGWDzcaBlgAzKhQa0EVNpPEKzQuBwZ8S8WaCeQ==", + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/supports-hyperlinks/-/supports-hyperlinks-2.3.0.tgz", + "integrity": "sha512-RpsAZlpWcDwOPQA22aCH4J0t7L8JmAvsCxfOSEwm7cQs3LshN36QaTkwd70DnBOXDWGssw2eUoc8CaRWT0XunA==", "dev": true, "requires": { "has-flag": "^4.0.0", @@ -8999,9 +9342,9 @@ "dev": true }, "typescript": { - "version": "4.7.4", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.7.4.tgz", - "integrity": "sha512-C0WQT0gezHuw6AdY1M2jxUO83Rjf0HP7Sk1DtXj6j1EwkQNZrHAg2XPWlq62oqEhYvONq5pkC2Y9oPljWToLmQ==", + "version": "4.8.4", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.8.4.tgz", + "integrity": "sha512-QCh+85mCy+h0IGff8r5XWzOVSbBO+KfeYrMQh7NJ58QujwcE22u+NUSmUxqF+un70P9GXKxa2HCNiTTMJknyjQ==", "dev": true }, "uhyphen": { @@ -9010,14 +9353,17 @@ "integrity": "sha512-o0QVGuFg24FK765Qdd5kk0zU/U4dEsCtN/GSiwNI9i8xsSVtjIAOdTaVhLwZ1nrbWxFVMxNDDl+9fednsOMsBw==" }, "undici": { - "version": "5.8.2", - "resolved": "https://registry.npmjs.org/undici/-/undici-5.8.2.tgz", - "integrity": "sha512-3KLq3pXMS0Y4IELV045fTxqz04Nk9Ms7yfBBHum3yxsTR4XNn+ZCaUbf/mWitgYDAhsplQ0B1G4S5D345lMO3A==" + "version": "5.12.0", + "resolved": "https://registry.npmjs.org/undici/-/undici-5.12.0.tgz", + "integrity": "sha512-zMLamCG62PGjd9HHMpo05bSLvvwWOZgGeiWlN/vlqu3+lRo3elxktVGEyLMX+IO7c2eflLjcW74AlkhEZm15mg==", + "requires": { + "busboy": "^1.6.0" + } }, "update-browserslist-db": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.4.tgz", - "integrity": "sha512-jnmO2BEGUjsMOe/Fg9u0oczOe/ppIDZPebzccl1yDWGLFP16Pa1/RM5wEoKYPG2zstNcDuAStejyxsOuKINdGA==", + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.10.tgz", + "integrity": "sha512-OztqDenkfFkbSG+tRxBeAnCVPckDBcvibKd35yDONx6OU8N7sqgwc7rCbkJ/WcYtVRZ4ba68d6byhC21GFh7sQ==", "dev": true, "requires": { "escalade": "^3.1.1", @@ -9033,12 +9379,6 @@ "punycode": "^2.1.0" } }, - "v8-compile-cache": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/v8-compile-cache/-/v8-compile-cache-2.3.0.tgz", - "integrity": "sha512-l8lCEmLcLYZh4nbunNZvQCJc5pv7+RCwa8q/LdUx8u7lsWvPDKmpodJAJNwkAhJC//dFY48KuIEmjtd4RViDrA==", - "dev": true - }, "v8-to-istanbul": { "version": "9.0.1", "resolved": "https://registry.npmjs.org/v8-to-istanbul/-/v8-to-istanbul-9.0.1.tgz", @@ -9092,9 +9432,9 @@ "dev": true }, "write-file-atomic": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-4.0.1.tgz", - "integrity": "sha512-nSKUxgAbyioruk6hU87QzVbY279oYT6uiwgDoujth2ju4mJ+TZau7SQBhtbTmUyuNYTuXnSyRn66FV0+eCgcrQ==", + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-4.0.2.tgz", + "integrity": "sha512-7KxauUdBmSdWnmpaGFg+ppNjKF8uNLry8LyzjauQDOVONfFLNKrKvQOxZ/VuTIcS/gge/YNahf5RIIQWTSarlg==", "dev": true, "requires": { "imurmurhash": "^0.1.4", @@ -9114,24 +9454,24 @@ "dev": true }, "yargs": { - "version": "17.5.1", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.5.1.tgz", - "integrity": "sha512-t6YAJcxDkNX7NFYiVtKvWUz8l+PaKTLiL63mJYWR2GnHq2gjEWISzsLp9wg3aY36dY1j+gfIEL3pIF+XlJJfbA==", + "version": "17.6.2", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.6.2.tgz", + "integrity": "sha512-1/9UrdHjDZc0eOU0HxOHoS78C69UD3JRMvzlJ7S79S2nTaWRA/whGCTV8o9e/N/1Va9YIV7Q4sOxD8VV4pCWOw==", "dev": true, "requires": { - "cliui": "^7.0.2", + "cliui": "^8.0.1", "escalade": "^3.1.1", "get-caller-file": "^2.0.5", "require-directory": "^2.1.1", "string-width": "^4.2.3", "y18n": "^5.0.5", - "yargs-parser": "^21.0.0" + "yargs-parser": "^21.1.1" } }, "yargs-parser": { - "version": "21.0.1", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.0.1.tgz", - "integrity": "sha512-9BK1jFpLzJROCI5TzwZL/TU4gqjK5xiHV/RfWLOahrjAko/e4DJkRDZQXfvqAsiZzzYhgAzbgz6lg48jcm4GLg==", + "version": "21.1.1", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz", + "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==", "dev": true }, "yocto-queue": { diff --git a/src/Innertube.ts b/src/Innertube.ts index a32ffb25..bf5db46d 100644 --- a/src/Innertube.ts +++ b/src/Innertube.ts @@ -27,25 +27,13 @@ import Proto from './proto/index'; import { throwIfMissing, generateRandomString } from './utils/Utils'; -export type InnertubeConfig = SessionOptions +export type InnertubeConfig = SessionOptions; export interface SearchFilters { - /** - * Filter videos by upload date, can be: any | last_hour | today | this_week | this_month | this_year - */ - upload_date?: 'any' | 'last_hour' | 'today' | 'this_week' | 'this_month' | 'this_year'; - /** - * Filter results by type, can be: any | video | channel | playlist | movie - */ - type?: 'any' | 'video' | 'channel' | 'playlist' | 'movie'; - /** - * Filter videos by duration, can be: any | short | medium | long - */ - duration?: 'any' | 'short' | 'medium' | 'long'; - /** - * Filter video results by order, can be: relevance | rating | upload_date | view_count - */ - sort_by?: 'relevance' | 'rating' | 'upload_date' | 'view_count'; + upload_date?: 'all' | 'hour' | 'today' | 'week' | 'month' | 'year', + type?: 'all' | 'video' | 'channel' | 'playlist' | 'movie', + duration?: 'all' | 'short' | 'medium' | 'long', + sort_by?: 'relevance' | 'rating' | 'upload_date' | 'view_count' } export type InnerTubeClient = 'WEB' | 'ANDROID' | 'YTMUSIC_ANDROID' | 'YTMUSIC' | 'TV_EMBEDDED'; @@ -75,12 +63,14 @@ class Innertube { /** * Retrieves video info. + * @param video_id - The video id. + * @param client - The client to use. */ async getInfo(video_id: string, client?: InnerTubeClient) { const cpn = generateRandomString(16); const initial_info = await this.actions.getVideoInfo(video_id, cpn, client); - const continuation = this.actions.next({ video_id }); + const continuation = this.actions.execute('/next', { videoId: video_id }); const response = await Promise.all([ initial_info, continuation ]); return new VideoInfo(response, this.actions, this.session.player, cpn); @@ -88,6 +78,8 @@ class Innertube { /** * Retrieves basic video info. + * @param video_id - The video id. + * @param client - The client to use. */ async getBasicInfo(video_id: string, client?: InnerTubeClient) { const cpn = generateRandomString(16); @@ -98,18 +90,27 @@ class Innertube { /** * Searches a given query. - * @param query - search query. - * @param filters - search filters. + * @param query - The search query. + * @param filters - Search filters. */ async search(query: string, filters: SearchFilters = {}) { throwIfMissing({ query }); - const response = await this.actions.search({ query, filters }); + + const args = { + query, + ...{ + params: filters ? Proto.encodeSearchFilters(filters) : undefined + } + }; + + const response = await this.actions.execute('/search', args); + return new Search(this.actions, response.data); } /** * Retrieves search suggestions for a given query. - * @param query - the search query. + * @param query - The search query. */ async getSearchSuggestions(query: string): Promise { throwIfMissing({ query }); @@ -134,8 +135,8 @@ class Innertube { /** * Retrieves comments for a video. - * @param video_id - the video id. - * @param sort_by - can be: `TOP_COMMENTS` or `NEWEST_FIRST`. + * @param video_id - The video id. + * @param sort_by - Sorting options. */ async getComments(video_id: string, sort_by?: 'TOP_COMMENTS' | 'NEWEST_FIRST') { throwIfMissing({ video_id }); @@ -144,7 +145,8 @@ class Innertube { sort_by: sort_by || 'TOP_COMMENTS' }); - const response = await this.actions.next({ ctoken: payload }); + const response = await this.actions.execute('/next', { continuation: payload }); + return new Comments(this.actions, response.data); } @@ -152,7 +154,7 @@ class Innertube { * Retrieves YouTube's home feed (aka recommendations). */ async getHomeFeed() { - const response = await this.actions.browse('FEwhat_to_watch'); + const response = await this.actions.execute('/browse', { browseId: 'FEwhat_to_watch' }); return new FilterableFeed(this.actions, response.data); } @@ -160,7 +162,7 @@ class Innertube { * Returns the account's library. */ async getLibrary() { - const response = await this.actions.browse('FElibrary'); + const response = await this.actions.execute('/browse', { browseId: 'FElibrary' }); return new Library(response.data, this.actions); } @@ -169,7 +171,7 @@ class Innertube { * Which can also be achieved with {@link getLibrary}. */ async getHistory() { - const response = await this.actions.browse('FEhistory'); + const response = await this.actions.execute('/browse', { browseId: 'FEhistory' }); return new History(this.actions, response.data); } @@ -177,7 +179,7 @@ class Innertube { * Retrieves trending content. */ async getTrending() { - const response = await this.actions.browse('FEtrending'); + const response = await this.actions.execute('/browse', { browseId: 'FEtrending' }); return new TabbedFeed(this.actions, response.data); } @@ -185,7 +187,7 @@ class Innertube { * Retrieves subscriptions feed. */ async getSubscriptionsFeed() { - const response = await this.actions.browse('FEsubscriptions'); + const response = await this.actions.execute('/browse', { browseId: 'FEsubscriptions' }); return new Feed(this.actions, response.data); } @@ -195,7 +197,7 @@ class Innertube { */ async getChannel(id: string) { throwIfMissing({ id }); - const response = await this.actions.browse(id); + const response = await this.actions.execute('/browse', { browseId: id }); return new Channel(this.actions, response.data); } @@ -203,7 +205,7 @@ class Innertube { * Retrieves notifications. */ async getNotifications() { - const response = await this.actions.notifications('get_notification_menu'); + const response = await this.actions.execute('/notification/get_notification_menu', { notificationsMenuRequestType: 'NOTIFICATIONS_MENU_REQUEST_TYPE_INBOX' }); return new NotificationsMenu(this.actions, response); } @@ -211,7 +213,7 @@ class Innertube { * Retrieves unseen notifications count. */ async getUnseenNotificationsCount() { - const response = await this.actions.notifications('get_unseen_count'); + const response = await this.actions.execute('/notification/get_unseen_count'); return response.data.unseenCount; } @@ -220,7 +222,12 @@ class Innertube { */ async getPlaylist(id: string) { throwIfMissing({ id }); - const response = await this.actions.browse(`VL${id}`); + + if (!id.startsWith('VL')) { + id = `VL${id}`; + } + + const response = await this.actions.execute('/browse', { browseId: id }); return new Playlist(this.actions, response.data); } @@ -245,10 +252,15 @@ class Innertube { return info.download(options); } + /** + * Utility method to call an endpoint without having to use {@link Actions}. + * @param endpoint -The endpoint to call. + * @param args - Call arguments. + */ call(endpoint: NavigationEndpoint, args: { [ key: string ]: any; parse: true }): Promise; call(endpoint: NavigationEndpoint, args?: { [ key: string ]: any; parse?: false }): Promise; call(endpoint: NavigationEndpoint, args?: object): Promise { - return endpoint.callTest(this.actions, args); + return endpoint.call(this.actions, args); } } diff --git a/src/core/AccountManager.ts b/src/core/AccountManager.ts index 59a2dd2e..70b06cd5 100644 --- a/src/core/AccountManager.ts +++ b/src/core/AccountManager.ts @@ -5,6 +5,7 @@ import Analytics from '../parser/youtube/Analytics'; import TimeWatched from '../parser/youtube/TimeWatched'; import AccountInfo from '../parser/youtube/AccountInfo'; import Settings from '../parser/youtube/Settings'; +import { InnertubeError } from '../utils/Utils'; class AccountManager { #actions; @@ -16,13 +17,30 @@ class AccountManager { this.channel = { /** * Edits channel name. + * @param new_name - The new channel name. */ - editName: (new_name: string) => this.#actions.channel('channel/edit_name', { new_name }), + editName: (new_name: string) => { + if (!this.#actions.session.logged_in) + throw new InnertubeError('You are not signed in'); + + return this.#actions.execute('/channel/edit_name', { + givenName: new_name, + client: 'ANDROID' + }); + }, /** * Edits channel description. - * + * @param new_description - The new description. */ - editDescription: (new_description: string) => this.#actions.channel('channel/edit_description', { new_description }), + editDescription: (new_description: string) => { + if (!this.#actions.session.logged_in) + throw new InnertubeError('You are not signed in'); + + return this.#actions.execute('/channel/edit_description', { + givenDescription: new_description, + client: 'ANDROID' + }); + }, /** * Retrieves basic channel analytics. */ @@ -34,6 +52,9 @@ class AccountManager { * Retrieves channel info. */ async getInfo() { + if (!this.#actions.session.logged_in) + throw new InnertubeError('You are not signed in'); + const response = await this.#actions.execute('/account/accounts_list', { client: 'ANDROID' }); return new AccountInfo(response); } @@ -68,7 +89,12 @@ class AccountManager { const info = await this.getInfo(); const params = Proto.encodeChannelAnalyticsParams(info.footers?.endpoint.payload.browseId); - const response = await this.#actions.browse('FEanalytics_screen', { params, client: 'ANDROID' }); + + const response = await this.#actions.execute('/browse', { + browseId: 'FEanalytics_screen', + client: 'ANDROID', + params + }); return new Analytics(response); } diff --git a/src/core/Actions.ts b/src/core/Actions.ts index 11fcd226..a08e3f8f 100644 --- a/src/core/Actions.ts +++ b/src/core/Actions.ts @@ -1,54 +1,14 @@ -import Proto from '../proto/index'; import Session from './Session'; - import Parser, { ParsedResponse } from '../parser/index'; +import { InnertubeError } from '../utils/Utils'; -import { hasKeys, InnertubeError, MissingParamError, uuidv4 } from '../utils/Utils'; - -export interface BrowseArgs { - params?: string | null; - is_ytm?: boolean; - is_ctoken?: boolean; - form_data?: {}; - client?: string; -} - -export interface EngageArgs { - video_id?: string; - channel_id?: string; - comment_id?: string; - comment_action?: string; - params?: string; - text?: string; - target_language?: string; -} - -export interface AccountArgs { - new_value?: string | boolean; // TODO: is this correct? - setting_item_id?: string; - client?: string; -} - -export interface SearchArgs { - query?: string, - options?: { - period?: string, - duration?: string, - order?: string - }, - client?: string, - ctoken?: string, - params?: string - filters?: any // TODO: what is this type?? -} - -export interface AxioslikeResponse { +export interface ApiResponse { success: boolean; status_code: number; data: any; } -export type ActionsResponse = Promise; +export type ActionsResponse = Promise; class Actions { #session; @@ -63,6 +23,7 @@ class Actions { /** * Mimmics the Axios API using Fetch's Response object. + * @param response - The response object. */ async #wrap(response: Response) { return { @@ -72,550 +33,12 @@ class Actions { }; } - /** - * Covers `/browse` endpoint, mostly used to access - * YouTube's sections such as the home feed, etc - * and sometimes to retrieve continuations. - * - * @param id - browseId or a continuation token - * @param args - additional arguments - */ - async browse(id: string, args: BrowseArgs = {}) { - if (this.#needsLogin(id) && !this.#session.logged_in) - throw new InnertubeError('You are not signed in'); - - const data: Record = {}; - - if (args.params) - data.params = args.params; - - if (args.is_ctoken) { - data.continuation = id; - } else { - data.browseId = id; - } - - if (args.form_data) { - data.formData = args.form_data; - } - - if (args.client) { - data.client = args.client; - } - - const response = await this.#session.http.fetch('/browse', { - method: 'POST', - body: JSON.stringify(data), - headers: { - 'Content-Type': 'application/json' - } - }); - - return this.#wrap(response); - } - - /** - * Covers endpoints used to perform direct interactions - * on YouTube. - */ - async engage(action: string, args: EngageArgs = {}) { - if (!this.#session.logged_in && !args.hasOwnProperty('text')) - throw new InnertubeError('You are not signed in'); - - const data: Record = {}; - - switch (action) { - case 'like/like': - case 'like/dislike': - case 'like/removelike': - if (!hasKeys(args, 'video_id')) - throw new MissingParamError('Arguments lacks video_id'); - - data.target = {}; - data.target.videoId = args.video_id; - - if (args.params) { - data.params = args.params; - } - break; - case 'subscription/subscribe': - case 'subscription/unsubscribe': - if (!hasKeys(args, 'channel_id')) - throw new MissingParamError('Arguments lacks channel_id'); - - data.channelIds = [ args.channel_id ]; - data.params = action === 'subscription/subscribe' ? 'EgIIAhgA' : 'CgIIAhgA'; - break; - case 'comment/create_comment': - data.commentText = args.text; - - if (!hasKeys(args, 'video_id')) - throw new MissingParamError('Arguments lacks video_id'); - - data.createCommentParams = Proto.encodeCommentParams(args.video_id); - break; - case 'comment/create_comment_reply': - if (!hasKeys(args, 'comment_id', 'video_id', 'text')) - throw new MissingParamError('Arguments lacks comment_id, video_id or text'); - - data.createReplyParams = Proto.encodeCommentReplyParams(args.comment_id, args.video_id); - data.commentText = args.text; - break; - case 'comment/perform_comment_action': - const target_action = (() => { - switch (args.comment_action) { - case 'like': - return Proto.encodeCommentActionParams(5, args); - case 'dislike': - return Proto.encodeCommentActionParams(4, args); - case 'translate': - return Proto.encodeCommentActionParams(22, args); - default: - break; - } - })(); - data.actions = [ target_action ]; - break; - default: - throw new InnertubeError('Action not implemented', action); - } - - const response = await this.#session.http.fetch(`/${action}`, { - method: 'POST', - body: JSON.stringify(data), - headers: { - 'Content-Type': 'application/json' - } - }); - - return this.#wrap(response); - } - - /** - * Covers endpoints related to account management. - */ - async account(action: string, args: AccountArgs = {}) { - if (!this.#session.logged_in) - throw new InnertubeError('You are not signed in'); - - const data: Record = { client: args.client }; - - switch (action) { - case 'account/set_setting': - data.newValue = { - boolValue: args.new_value - }; - data.settingItemId = args.setting_item_id; - break; - case 'account/accounts_list': - break; - default: - throw new InnertubeError('Action not implemented', action); - } - - const response = await this.#session.http.fetch(`/${action}`, { - method: 'POST', - body: JSON.stringify(data), - headers: { - 'Content-Type': 'application/json' - } - }); - - return this.#wrap(response); - } - - /** - * Endpoint used for search. - */ - async search(args: SearchArgs = {}) { - const data: Record = { client: args.client }; - - if (args.query) { - data.query = args.query; - } - - if (args.ctoken) { - data.continuation = args.ctoken; - } - - if (args.params) { - data.params = args.params; - } - - if (args.filters) { - if (args.client == 'YTMUSIC' && args.filters?.type && args.filters.type !== 'all') { - data.params = Proto.encodeMusicSearchFilters(args.filters); - } else { - data.params = Proto.encodeSearchFilters(args.filters); - } - } - - const response = await this.#session.http.fetch('/search', { - method: 'POST', - body: JSON.stringify(data), - headers: { - 'Content-Type': 'application/json' - } - }); - - return this.#wrap(response); - } - - /** - * Endpoint used fo Shorts' sound search. - */ - async searchSound(args: { query: string; }) { - const data = { - query: args.query, - client: 'ANDROID' - }; - - const response = await this.#session.http.fetch('/sfv/search', { - method: 'POST', - body: JSON.stringify(data), - headers: { - 'Content-Type': 'application/json' - } - }); - - return this.#wrap(response); - } - - /** - * Channel management endpoints. - */ - async channel(action: string, args: { new_name?: string; new_description?: string; client?: string; } = {}) { - if (!this.#session.logged_in) - throw new InnertubeError('You are not signed in'); - - const data: Record = { client: args.client || 'ANDROID' }; - - switch (action) { - case 'channel/edit_name': - data.givenName = args.new_name; - break; - case 'channel/edit_description': - data.description = args.new_description; - break; - case 'channel/get_profile_editor': - break; - default: - throw new InnertubeError('Action not implemented', action); - } - - const response = await this.#session.http.fetch(`/${action}`, { - method: 'POST', - body: JSON.stringify(data), - headers: { - 'Content-Type': 'application/json' - } - }); - - return this.#wrap(response); - } - - /** - * Covers endpoints used for playlist management. - */ - async playlist(action: string, args: { - title?: string; - ids?: string[]; - playlist_id?: string; - action?: string; - } = {}) { - if (!this.#session.logged_in) - throw new InnertubeError('You are not signed in'); - - const data: Record = {}; - - switch (action) { - case 'playlist/create': - data.title = args.title; - data.videoIds = args.ids; - break; - case 'playlist/delete': - data.playlistId = args.playlist_id; - break; - case 'browse/edit_playlist': - if (!hasKeys(args, 'ids')) - throw new MissingParamError('Arguments lacks ids'); - data.playlistId = args.playlist_id; - data.actions = args.ids.map((id) => { - switch (args.action) { - case 'ACTION_ADD_VIDEO': - return { - action: args.action, - addedVideoId: id - }; - case 'ACTION_REMOVE_VIDEO': - return { - action: args.action, - setVideoId: id - }; - default: - break; - } - }); - break; - default: - throw new InnertubeError('Action not implemented', action); - } - - const response = await this.#session.http.fetch(`/${action}`, { - method: 'POST', - body: JSON.stringify(data), - headers: { - 'Content-Type': 'application/json' - } - }); - - return this.#wrap(response); - } - - /** - * Covers endpoints used for notifications management. - */ - async notifications(action: string, args: { - pref?: string; - channel_id?: string; - ctoken?: string; - params?: string - } = {}) { - if (!this.#session.logged_in) - throw new InnertubeError('You are not signed in'); - - const data: Record = {}; - - switch (action) { - case 'modify_channel_preference': - if (!hasKeys(args, 'channel_id', 'pref')) - throw new MissingParamError('Arguments lacks channel_id or pref'); - const pref_types = { - PERSONALIZED: 1, - ALL: 2, - NONE: 3 - }; - if (!Object.keys(pref_types).includes(args.pref.toUpperCase())) - throw new InnertubeError('Invalid preference type', args.pref); - data.params = Proto.encodeNotificationPref(args.channel_id, pref_types[args.pref.toUpperCase() as keyof typeof pref_types]); - break; - case 'get_notification_menu': - data.notificationsMenuRequestType = 'NOTIFICATIONS_MENU_REQUEST_TYPE_INBOX'; - if (args.ctoken) - data.ctoken = args.ctoken; - break; - case 'record_interactions': - data.serializedRecordNotificationInteractionsRequest = args.params; - break; - case 'get_unseen_count': - break; - default: - throw new InnertubeError('Action not implemented', action); - } - - const response = await this.#session.http.fetch(`/notification/${action}`, { - method: 'POST', - body: JSON.stringify(data), - headers: { - 'Content-Type': 'application/json' - } - }); - - return this.#wrap(response); - } - - /** - * Covers livechat endpoints. - */ - async livechat(action: string, args: { - text?: string; - video_id?: string; - channel_id?: string; - ctoken?: string; - params?: string; - client?: string; - } = {}) { - // TODO: should client be required? - const data: Record = { client: args.client }; - - switch (action) { - case 'live_chat/get_live_chat': - case 'live_chat/get_live_chat_replay': - data.continuation = args.ctoken; - break; - case 'live_chat/send_message': - if (!hasKeys(args, 'channel_id', 'video_id', 'text')) - throw new MissingParamError('Arguments lacks channel_id, video_id or text'); - data.params = Proto.encodeMessageParams(args.channel_id, args.video_id); - data.clientMessageId = uuidv4(); - data.richMessage = { - textSegments: [ { - text: args.text - } ] - }; - break; - case 'live_chat/get_item_context_menu': - data.params = args.params; - break; - case 'live_chat/moderate': - data.params = args.params; - break; - case 'updated_metadata': - data.videoId = args.video_id; - if (args.ctoken) - data.continuation = args.ctoken; - break; - default: - throw new InnertubeError('Action not implemented', action); - } - - const response = await this.#session.http.fetch(`/${action}`, { - method: 'POST', - body: JSON.stringify(data), - headers: { - 'Content-Type': 'application/json' - } - }); - - return this.#wrap(response); - } - - /** - * Endpoint used to retrieve video thumbnails. - */ - async thumbnails(args: { video_id: string; }) { - const data = { - client: 'ANDROID', - videoId: args.video_id - }; - - const response = await this.#session.http.fetch('/thumbnails', { - method: 'POST', - body: JSON.stringify(data), - headers: { - 'Content-Type': 'application/json' - } - }); - - return this.#wrap(response); - } - - /** - * Place Autocomplete endpoint, found it in the APK but - * doesn't seem to be used anywhere on YouTube (maybe for ads?). - * - * Ex: - * ```js - * const places = await session.actions.geo('place_autocomplete', { input: 'San diego cafe' }); - * console.info(places.data); - * ``` - */ - async geo(action: string, args: { input: string; }) { - if (!this.#session.logged_in) - throw new InnertubeError('You are not signed in'); - - const data = { - input: args.input, - client: 'ANDROID' - }; - - const response = await this.#session.http.fetch(`/geo/${action}`, { - method: 'POST', - body: JSON.stringify(data), - headers: { - 'Content-Type': 'application/json' - } - }); - - return this.#wrap(response); - } - - /** - * Covers endpoints used to report content. - */ - async flag(action: string, args: { action: string; params?: string; }) { - if (!this.#session.logged_in) - throw new InnertubeError('You are not signed in'); - - const data: Record = {}; - - switch (action) { - case 'flag/flag': - data.action = args.action; - break; - case 'flag/get_form': - data.params = args.params; - break; - default: - throw new InnertubeError('Action not implemented', action); - } - - const response = await this.#session.http.fetch(`/${action}`, { - method: 'POST', - body: JSON.stringify(data), - headers: { - 'Content-Type': 'application/json' - } - }); - - return this.#wrap(response); - } - - /** - * Covers specific YouTube Music endpoints. - */ - async music(action: string, args: { input?: string; }) { - const data = { - input: args.input || '', - client: 'YTMUSIC' - }; - - const response = await this.#session.http.fetch(`/music/${action}`, { - method: 'POST', - body: JSON.stringify(data), - headers: { - 'Content-Type': 'application/json' - } - }); - - return this.#wrap(response); - } - - /** - * Mostly used for pagination and specific operations. - */ - async next(args: { video_id?: string; ctoken?: string; client?: string; playlist_id?: string; params?: string } = {}) { - const data: Record = { client: args.client }; - - if (args.ctoken) { - data.continuation = args.ctoken; - } - - if (args.video_id) { - data.videoId = args.video_id; - } - - if (args.playlist_id) { - data.playlistId = args.playlist_id; - } - - if (args.params) { - data.params = args.params; - } - - const response = await this.#session.http.fetch('/next', { - method: 'POST', - body: JSON.stringify(data), - headers: { - 'Content-Type': 'application/json' - } - }); - - return this.#wrap(response); - } - /** * Used to retrieve video info. + * @param id - The video ID. + * @param cpn - Content Playback Nonce. + * @param client - The client to use. + * @param playlist_id - The playlist ID. */ async getVideoInfo(id: string, cpn?: string, client?: string, playlist_id?: string) { const data: Record = { @@ -661,31 +84,11 @@ class Actions { return this.#wrap(response); } - /** - * Endpoint used to retrieve user mention suggestions. - */ - async getUserMentionSuggestions(args: { input: string; }) { - if (!this.#session.logged_in) - throw new InnertubeError('You are not signed in'); - - const data = { - input: args.input, - client: 'ANDROID' - }; - - const response = await this.#session.http.fetch('/get_user_mention_suggestions', { - method: 'POST', - body: JSON.stringify(data), - headers: { - 'Content-Type': 'application/json' - } - }); - - return this.#wrap(response); - } - /** * Makes calls to the playback tracking API. + * @param url - The URL to call. + * @param client - The client to use. + * @param params - Call parameters. */ async stats(url: string, client: { client_name: string; client_version: string }, params: { [key: string]: any }) { const s_url = new URL(url); @@ -706,15 +109,15 @@ class Actions { /** * Executes an API call. - * @param action - endpoint - * @param args - call arguments + * @param action - The endpoint to call. + * @param args - Call arguments */ async execute(action: string, args: { [key: string]: any; parse: true; protobuf?: false; serialized_data?: any }) : Promise; - async execute(action: string, args: { [key: string]: any; parse?: false; protobuf?: true; serialized_data?: any }) : Promise; - async execute(action: string, args: { [key: string]: any; parse?: boolean; protobuf?: boolean; serialized_data?: any }): Promise { + async execute(action: string, args?: { [key: string]: any; parse?: false; protobuf?: true; serialized_data?: any }) : Promise; + async execute(action: string, args?: { [key: string]: any; parse?: boolean; protobuf?: boolean; serialized_data?: any }): Promise { let data; - if (!args.protobuf) { + if (args && !args.protobuf) { data = { ...args }; if (Reflect.has(data, 'browseId')) { @@ -755,23 +158,23 @@ class Actions { if (data?.client === 'YTMUSIC') { data.isAudioOnly = true; } - } else { + } else if (args) { data = args.serialized_data; } - const endpoint = Reflect.has(args, 'override_endpoint') ? args.override_endpoint : action; + const endpoint = Reflect.has(args || {}, 'override_endpoint') ? args?.override_endpoint : action; const response = await this.#session.http.fetch(endpoint, { method: 'POST', - body: args.protobuf ? data : JSON.stringify(data), + body: args?.protobuf ? data : JSON.stringify(data), headers: { - 'Content-Type': args.protobuf ? + 'Content-Type': args?.protobuf ? 'application/x-protobuf' : 'application/json' } }); - if (args.parse) { + if (args?.parse) { return Parser.parseResponse(await response.json()); } @@ -784,6 +187,7 @@ class Actions { 'FEhistory', 'FEsubscriptions', 'FEmusic_listening_review', + 'FEmusic_library_landing', 'SPaccount_notifications', 'SPaccount_privacy', 'SPtime_watched' @@ -791,5 +195,4 @@ class Actions { } } -// TODO: maybe do this inferrance in a more elegant way export default Actions; \ No newline at end of file diff --git a/src/core/Feed.ts b/src/core/Feed.ts index 106bf167..eaa94c5c 100644 --- a/src/core/Feed.ts +++ b/src/core/Feed.ts @@ -1,6 +1,6 @@ import Parser, { ParsedResponse, ReloadContinuationItemsCommand } from '../parser/index'; import { Memo, ObservedArray } from '../parser/helpers'; -import { InnertubeError } from '../utils/Utils'; +import { concatMemos, InnertubeError } from '../utils/Utils'; import Actions from './Actions'; import Post from '../parser/classes/Post'; @@ -30,7 +30,6 @@ import ContinuationItem from '../parser/classes/ContinuationItem'; import Video from '../parser/classes/Video'; -// TODO: add a way subdivide into sections and return subfeeds? class Feed { #page: ParsedResponse; #continuation?: ObservedArray; @@ -44,16 +43,14 @@ class Feed { this.#page = Parser.parseResponse(data); } - // Xxx: this can be extremely confusing — maybe refactor? - const memo = - this.#page.on_response_received_commands ? - this.#page.on_response_received_commands_memo : - this.#page.on_response_received_endpoints ? - this.#page.on_response_received_endpoints_memo : - this.#page.contents ? - this.#page.contents_memo : - this.#page.on_response_received_actions ? - this.#page.on_response_received_actions_memo : undefined; + const memo = concatMemos( + this.#page.contents_memo, + this.#page.on_response_received_commands_memo, + this.#page.on_response_received_endpoints_memo, + this.#page.on_response_received_actions_memo, + this.#page.sidebar_memo, + this.#page.header_memo + ); if (!memo) throw new InnertubeError('No memo found in feed'); @@ -183,7 +180,7 @@ class Feed { if (this.#continuation.length === 0) throw new InnertubeError('There are no continuations'); - const response = await this.#continuation[0].endpoint.call(this.#actions, undefined, true); + const response = await this.#continuation[0].endpoint.call(this.#actions, { parse: true }); return response; } diff --git a/src/core/FilterableFeed.ts b/src/core/FilterableFeed.ts index a9e0de97..cbbc63f8 100644 --- a/src/core/FilterableFeed.ts +++ b/src/core/FilterableFeed.ts @@ -57,7 +57,8 @@ class FilterableFeed extends Feed { if (target_filter.is_selected) return this; - const response = await target_filter.endpoint?.call(this.actions, undefined, true); + const response = await target_filter.endpoint?.call(this.actions, { parse: true }); + return new Feed(this.actions, response, true); } } diff --git a/src/core/InteractionManager.ts b/src/core/InteractionManager.ts index 2dcf2dfa..f646422b 100644 --- a/src/core/InteractionManager.ts +++ b/src/core/InteractionManager.ts @@ -1,5 +1,6 @@ -import { throwIfMissing } from '../utils/Utils'; +import Proto from '../proto'; import Actions from './Actions'; +import { throwIfMissing } from '../utils/Utils'; class InteractionManager { #actions; @@ -10,55 +11,119 @@ class InteractionManager { /** * Likes a given video. + * @param video_id - The video ID */ async like(video_id: string) { throwIfMissing({ video_id }); - const action = await this.#actions.engage('like/like', { video_id }); + + if (!this.#actions.session.logged_in) + throw new Error('You are not signed in'); + + const action = await this.#actions.execute('/like/like', { + client: 'ANDROID', + target: { + videoId: video_id + } + }); + return action; } /** * Dislikes a given video. + * @param video_id - The video ID */ async dislike(video_id: string) { throwIfMissing({ video_id }); - const action = await this.#actions.engage('like/dislike', { video_id }); + + if (!this.#actions.session.logged_in) + throw new Error('You are not signed in'); + + const action = await this.#actions.execute('/like/dislike', { + client: 'ANDROID', + target: { + videoId: video_id + } + }); + return action; } /** * Removes a like/dislike. + * @param video_id - The video ID */ - async removeLike(video_id: string) { + async removeRating(video_id: string) { throwIfMissing({ video_id }); - const action = await this.#actions.engage('like/removelike', { video_id }); + + if (!this.#actions.session.logged_in) + throw new Error('You are not signed in'); + + const action = await this.#actions.execute('/like/removelike', { + client: 'ANDROID', + target: { + videoId: video_id + } + }); + return action; } /** * Subscribes to a given channel. + * @param channel_id - The channel ID */ async subscribe(channel_id: string) { throwIfMissing({ channel_id }); - const action = await this.#actions.engage('subscription/subscribe', { channel_id }); + + if (!this.#actions.session.logged_in) + throw new Error('You are not signed in'); + + const action = await this.#actions.execute('/subscription/subscribe', { + client: 'ANDROID', + channelIds: [ channel_id ], + params: 'EgIIAhgA' + }); + return action; } /** * Unsubscribes from a given channel. + * @param channel_id - The channel ID */ async unsubscribe(channel_id: string) { throwIfMissing({ channel_id }); - const action = await this.#actions.engage('subscription/unsubscribe', { channel_id }); + + if (!this.#actions.session.logged_in) + throw new Error('You are not signed in'); + + const action = await this.#actions.execute('/subscription/unsubscribe', { + client: 'ANDROID', + channelIds: [ channel_id ], + params: 'CgIIAhgA' + }); + return action; } /** * Posts a comment on a given video. + * @param video_id - The video ID + * @param text - The comment text */ async comment(video_id: string, text: string) { throwIfMissing({ video_id, text }); - const action = await this.#actions.engage('comment/create_comment', { video_id, text }); + + if (!this.#actions.session.logged_in) + throw new Error('You are not signed in'); + + const action = await this.#actions.execute('/comment/create_comment', { + client: 'ANDROID', + commentText: text, + createCommentParams: Proto.encodeCommentParams(video_id) + }); + return action; } @@ -71,12 +136,11 @@ class InteractionManager { async translate(text: string, target_language: string, args: { video_id?: string; comment_id?: string; } = {}) { throwIfMissing({ text, target_language }); - const response = await await this.#actions.engage('comment/perform_comment_action', { - video_id: args.video_id, - comment_id: args.comment_id, - target_language: target_language, - comment_action: 'translate', - text + const target_action = Proto.encodeCommentActionParams(22, { text, target_language, ...args }); + + const response = await this.#actions.execute('/comment/perform_comment_action', { + client: 'ANDROID', + actions: [ target_action ] }); const mutation = response.data.frameworkUpdates.entityBatchUpdate.mutations[0].payload.commentEntityPayload; @@ -92,10 +156,29 @@ class InteractionManager { /** * Changes notification preferences for a given channel. * Only works with channels you are subscribed to. + * @param channel_id - The channel ID. + * @param type - The notification type. */ async setNotificationPreferences(channel_id: string, type: 'PERSONALIZED' | 'ALL' | 'NONE') { throwIfMissing({ channel_id, type }); - const action = await this.#actions.notifications('modify_channel_preference', { channel_id, pref: type || 'NONE' }); + + if (!this.#actions.session.logged_in) + throw new Error('You are not signed in'); + + const pref_types = { + PERSONALIZED: 1, + ALL: 2, + NONE: 3 + }; + + if (!Object.keys(pref_types).includes(type.toUpperCase())) + throw new Error(`Invalid notification preference type: ${type}`); + + const action = await this.#actions.execute('/notification/modify_channel_preference', { + client: 'ANDROID', + params: Proto.encodeNotificationPref(channel_id, pref_types[type.toUpperCase() as keyof typeof pref_types]) + }); + return action; } } diff --git a/src/core/Music.ts b/src/core/Music.ts index 77e7a5bf..d5fa6d0b 100644 --- a/src/core/Music.ts +++ b/src/core/Music.ts @@ -27,6 +27,7 @@ import MusicTwoRowItem from '../parser/classes/MusicTwoRowItem'; import { observe, ObservedArray, YTNode } from '../parser/helpers'; import { InnertubeError, throwIfMissing, generateRandomString } from '../utils/Utils'; +import Proto from '../proto'; class Music { #session; @@ -39,7 +40,7 @@ class Music { /** * Retrieves track info. Passing a list item of type MusicTwoRowItem automatically starts a radio. - * @param target - video id or a list item. + * @param target - Video id or a list item. */ getInfo(target: string | MusicTwoRowItem): Promise { if (target instanceof MusicTwoRowItem) { @@ -83,7 +84,7 @@ class Music { const cpn = generateRandomString(16); - const initial_info = list_item.endpoint.callTest(this.#actions, { + const initial_info = list_item.endpoint.call(this.#actions, { cpn, client: 'YTMUSIC', playbackContext: { @@ -93,7 +94,7 @@ class Music { } }); - const continuation = list_item.endpoint.callTest(this.#actions, { + const continuation = list_item.endpoint.call(this.#actions, { client: 'YTMUSIC', enablePersistentPlaylistPanel: true, override_endpoint: '/next' @@ -105,12 +106,26 @@ class Music { /** * Searches on YouTube Music. + * @param query - Search query. + * @param filters - Search filters. */ async search(query: string, filters: { type?: 'all' | 'song' | 'video' | 'album' | 'playlist' | 'artist'; } = {}): Promise { throwIfMissing({ query }); - const response = await this.#actions.search({ query, filters, client: 'YTMUSIC' }); + + const payload: { + query: string; + client: string; + params?: string; + } = { query, client: 'YTMUSIC' }; + + if (filters.type && filters.type !== 'all') { + payload.params = Proto.encodeMusicSearchFilters(filters); + } + + const response = await this.#actions.execute('/search', payload); + return new Search(response, this.#actions, { is_filtered: Reflect.has(filters, 'type') && filters.type !== 'all' }); } @@ -118,7 +133,11 @@ class Music { * Retrieves the home feed. */ async getHomeFeed(): Promise { - const response = await this.#actions.browse('FEmusic_home', { client: 'YTMUSIC' }); + const response = await this.#actions.execute('/browse', { + client: 'YTMUSIC', + browseId: 'FEmusic_home' + }); + return new HomeFeed(response, this.#actions); } @@ -126,20 +145,30 @@ class Music { * Retrieves the Explore feed. */ async getExplore(): Promise { - const response = await this.#actions.browse('FEmusic_explore', { client: 'YTMUSIC' }); + const response = await this.#actions.execute('/browse', { + client: 'YTMUSIC', + browseId: 'FEmusic_explore' + }); + return new Explore(response); // TODO: return new Explore(response, this.#actions); } /** - * Retrieves the Library. + * Retrieves the library. */ - getLibrary() { - return new Library(this.#actions); + async getLibrary(): Promise { + const response = await this.#actions.execute('/browse', { + client: 'YTMUSIC', + browseId: 'FEmusic_library_landing' + }); + + return new Library(response, this.#actions); } /** * Retrieves artist's info & content. + * @param artist_id - The artist id. */ async getArtist(artist_id: string): Promise { throwIfMissing({ artist_id }); @@ -147,12 +176,17 @@ class Music { if (!artist_id.startsWith('UC') && !artist_id.startsWith('FEmusic_library_privately_owned_artist')) throw new InnertubeError('Invalid artist id', artist_id); - const response = await this.#actions.browse(artist_id, { client: 'YTMUSIC' }); + const response = await this.#actions.execute('/browse', { + client: 'YTMUSIC', + browseId: artist_id + }); + return new Artist(response, this.#actions); } /** * Retrieves album. + * @param album_id - The album id. */ async getAlbum(album_id: string): Promise { throwIfMissing({ album_id }); @@ -160,12 +194,17 @@ class Music { if (!album_id.startsWith('MPR') && !album_id.startsWith('FEmusic_library_privately_owned_release')) throw new InnertubeError('Invalid album id', album_id); - const response = await this.#actions.browse(album_id, { client: 'YTMUSIC' }); + const response = await this.#actions.execute('/browse', { + client: 'YTMUSIC', + browseId: album_id + }); + return new Album(response, this.#actions); } /** * Retrieves playlist. + * @param playlist_id - The playlist id. */ async getPlaylist(playlist_id: string): Promise { throwIfMissing({ playlist_id }); @@ -174,12 +213,18 @@ class Music { playlist_id = `VL${playlist_id}`; } - const response = await this.#actions.browse(playlist_id, { client: 'YTMUSIC' }); + const response = await this.#actions.execute('/browse', { + client: 'YTMUSIC', + browseId: playlist_id + }); + return new Playlist(response, this.#actions); } /** * Retrieves up next. + * @param video_id - The video id. + * @param automix - Whether to enable automix. */ async getUpNext(video_id: string, automix = true): Promise { throwIfMissing({ video_id }); @@ -214,7 +259,7 @@ class Music { if (!automix_preview_video) throw new InnertubeError('Automix item not found'); - const page = await automix_preview_video.playlist_video?.endpoint.callTest(this.#actions, { + const page = await automix_preview_video.playlist_video?.endpoint.call(this.#actions, { videoId: video_id, client: 'YTMUSIC', parse: true @@ -231,6 +276,7 @@ class Music { /** * Retrieves related content. + * @param video_id - The video id. */ async getRelated(video_id: string): Promise> { throwIfMissing({ video_id }); @@ -252,10 +298,7 @@ class Music { if (!tab) throw new InnertubeError('Could not find target tab.'); - const page = await tab.endpoint.call(this.#actions, 'YTMUSIC', true); - - if (!page) - throw new InnertubeError('Could not retrieve tab contents, the given id may be invalid or is not a song.'); + const page = await tab.endpoint.call(this.#actions, { client: 'YTMUSIC', parse: true }); const shelves = page.contents.item().as(SectionList).contents.array().as(MusicCarouselShelf, MusicDescriptionShelf); @@ -264,6 +307,7 @@ class Music { /** * Retrieves song lyrics. + * @param video_id - The video id. */ async getLyrics(video_id: string): Promise { throwIfMissing({ video_id }); @@ -285,10 +329,7 @@ class Music { if (!tab) throw new InnertubeError('Could not find target tab.'); - const page = await tab.endpoint.call(this.#actions, 'YTMUSIC', true); - - if (!page) - throw new InnertubeError('Could not retrieve tab contents, the given id may be invalid or is not a song.'); + const page = await tab.endpoint.call(this.#actions, { client: 'YTMUSIC', parse: true }); if (page.contents.item().key('type').string() === 'Message') throw new InnertubeError(page.contents.item().as(Message).text, video_id); @@ -311,6 +352,7 @@ class Music { /** * Retrieves search suggestions for the given query. + * @param query - The query. */ async getSearchSuggestions(query: string) { const response = await this.#actions.execute('/music/get_search_suggestions', { @@ -321,7 +363,7 @@ class Music { const search_suggestions_section = response.contents_memo.getType(SearchSuggestionsSection)?.[0]; - if (!search_suggestions_section.contents.is_array) + if (!search_suggestions_section?.contents.is_array) return observe([] as YTNode[]); return search_suggestions_section?.contents.array(); diff --git a/src/core/OAuth.ts b/src/core/OAuth.ts index 052df8c9..fd77e1b4 100644 --- a/src/core/OAuth.ts +++ b/src/core/OAuth.ts @@ -241,7 +241,6 @@ class OAuth { .replace(/\n/g, '') .match(Constants.OAUTH.REGEX.CLIENT_IDENTITY); - // TODO: check this. const groups = client_identity?.groups; if (!groups) diff --git a/src/core/PlaylistManager.ts b/src/core/PlaylistManager.ts index e476d06a..d875132b 100644 --- a/src/core/PlaylistManager.ts +++ b/src/core/PlaylistManager.ts @@ -13,11 +13,20 @@ class PlaylistManager { /** * Creates a playlist. + * @param title - The title of the playlist. + * @param video_ids - An array of video IDs to add to the playlist. */ async create(title: string, video_ids: string[]) { throwIfMissing({ title, video_ids }); - const response = await this.#actions.execute('/playlist/create', { title, ids: video_ids, parse: false }); + if (!this.#actions.session.logged_in) + throw new InnertubeError('You are not signed in'); + + const response = await this.#actions.execute('/playlist/create', { + title, + ids: video_ids, + parse: false + }); return { success: response.success, @@ -29,10 +38,14 @@ class PlaylistManager { /** * Deletes a given playlist. + * @param playlist_id - The playlist ID. */ async delete(playlist_id: string) { throwIfMissing({ playlist_id }); + if (!this.#actions.session.logged_in) + throw new InnertubeError('You are not signed in'); + const response = await this.#actions.execute('playlist/delete', { playlistId: playlist_id }); return { @@ -45,10 +58,15 @@ class PlaylistManager { /** * Adds videos to a given playlist. + * @param playlist_id - The playlist ID. + * @param video_ids - An array of video IDs to add to the playlist. */ async addVideos(playlist_id: string, video_ids: string[]) { throwIfMissing({ playlist_id, video_ids }); + if (!this.#actions.session.logged_in) + throw new InnertubeError('You are not signed in'); + const response = await this.#actions.execute('/browse/edit_playlist', { playlistId: playlist_id, actions: video_ids.map((id) => ({ @@ -66,11 +84,20 @@ class PlaylistManager { /** * Removes videos from a given playlist. + * @param playlist_id - The playlist ID. + * @param video_ids - An array of video IDs to remove from the playlist. */ async removeVideos(playlist_id: string, video_ids: string[]) { throwIfMissing({ playlist_id, video_ids }); - const info = await this.#actions.execute('/browse', { browseId: `VL${playlist_id}`, parse: true }); + if (!this.#actions.session.logged_in) + throw new InnertubeError('You are not signed in'); + + const info = await this.#actions.execute('/browse', { + browseId: `VL${playlist_id}`, + parse: true + }); + const playlist = new Playlist(this.#actions, info, true); if (!playlist.info.is_editable) @@ -115,11 +142,21 @@ class PlaylistManager { /** * Moves a video to a new position within a given playlist. + * @param playlist_id - The playlist ID. + * @param moved_video_id - The video ID to move. + * @param predecessor_video_id - The video ID to move the moved video before. */ async moveVideo(playlist_id: string, moved_video_id: string, predecessor_video_id: string) { throwIfMissing({ playlist_id, moved_video_id, predecessor_video_id }); - const info = await this.#actions.execute('/browse', { browseId: `VL${playlist_id}`, parse: true }); + if (!this.#actions.session.logged_in) + throw new InnertubeError('You are not signed in'); + + const info = await this.#actions.execute('/browse', { + browseId: `VL${playlist_id}`, + parse: true + }); + const playlist = new Playlist(this.#actions, info, true); if (!playlist.info.is_editable) @@ -157,7 +194,10 @@ class PlaylistManager { movedSetVideoIdPredecessor: set_video_id_1 }); - const response = await this.#actions.execute('/browse/edit_playlist', { ...payload, parse: false }); + const response = await this.#actions.execute('/browse/edit_playlist', { + ...payload, + parse: false + }); return { playlist_id, diff --git a/src/core/Studio.ts b/src/core/Studio.ts index c46ba388..e4f1a1ef 100644 --- a/src/core/Studio.ts +++ b/src/core/Studio.ts @@ -1,6 +1,6 @@ import Proto from '../proto'; import Session from './Session'; -import { AxioslikeResponse } from './Actions'; +import { ApiResponse } from './Actions'; import { InnertubeError, MissingParamError, uuidv4 } from '../utils/Utils'; import { Constants } from '../utils'; @@ -50,7 +50,10 @@ class Studio { * const response = await yt.studio.setThumbnail(video_id, buffer); * ``` */ - async setThumbnail(video_id: string, buffer: Uint8Array): Promise { + async setThumbnail(video_id: string, buffer: Uint8Array): Promise { + if (!this.#session.logged_in) + throw new InnertubeError('You are not signed in'); + if (!video_id || !buffer) throw new MissingParamError('One or more parameters are missing.'); @@ -79,6 +82,9 @@ class Studio { * ``` */ async updateVideoMetadata(video_id: string, metadata: VideoMetadata) { + if (!this.#session.logged_in) + throw new InnertubeError('You are not signed in'); + const payload = Proto.encodeVideoMetadataPayload(video_id, metadata); const response = await this.#session.actions.execute('/video_manager/metadata_update', { @@ -97,7 +103,10 @@ class Studio { * const response = await yt.studio.upload(file.buffer, { title: 'Wow!' }); * ``` */ - async upload(file: BodyInit, metadata: UploadedVideoMetadata = {}): Promise { + async upload(file: BodyInit, metadata: UploadedVideoMetadata = {}): Promise { + if (!this.#session.logged_in) + throw new InnertubeError('You are not signed in'); + const initial_data = await this.#getInitialUploadData(); const upload_result = await this.#uploadVideo(initial_data.upload_url, file); diff --git a/src/parser/classes/Grid.ts b/src/parser/classes/Grid.ts index 05ac3622..c9583016 100644 --- a/src/parser/classes/Grid.ts +++ b/src/parser/classes/Grid.ts @@ -5,23 +5,34 @@ class Grid extends YTNode { static type = 'Grid'; items; - is_collapsible: boolean; - visible_row_count: string; - target_id: string; + is_collapsible?: boolean; + visible_row_count?: string; + target_id?: string; continuation: string | null; header?; constructor(data: any) { super(); - this.items = Parser.parse(data.items); - this.is_collapsible = data.isCollapsible; - this.visible_row_count = data.visibleRowCount; - this.target_id = data.targetId; - this.continuation = data.continuations?.[0]?.nextContinuationData?.continuation || null; + + this.items = Parser.parseArray(data.items); if (data.header) { this.header = Parser.parse(data.header); } + + if (data.isCollapsible) { + this.is_collapsible = data.isCollapsible; + } + + if (data.visibleRowCount) { + this.visible_row_count = data.visibleRowCount; + } + + if (data.targetId) { + this.target_id = data.targetId; + } + + this.continuation = data.continuations?.[0]?.nextContinuationData?.continuation || null; } // XXX: alias for consistency diff --git a/src/parser/classes/MusicDetailHeader.ts b/src/parser/classes/MusicDetailHeader.ts index af731731..3168a254 100644 --- a/src/parser/classes/MusicDetailHeader.ts +++ b/src/parser/classes/MusicDetailHeader.ts @@ -36,12 +36,12 @@ class MusicDetailHeader extends YTNode { this.thumbnails = Thumbnail.fromResponse(data.thumbnail.croppedSquareThumbnailRenderer.thumbnail); this.badges = Parser.parse(data.subtitleBadges); - const author = this.subtitle.runs?.find((run) => (run as TextRun)?.endpoint?.browse?.id.startsWith('UC')); + const author = this.subtitle.runs?.find((run) => (run as TextRun)?.endpoint?.payload?.browseId.startsWith('UC')); if (author) { this.author = { name: (author as TextRun).text, - channel_id: (author as TextRun).endpoint?.browse?.id, + channel_id: (author as TextRun).endpoint?.payload?.browseId, endpoint: (author as TextRun).endpoint }; } diff --git a/src/parser/classes/MusicResponsiveListItem.ts b/src/parser/classes/MusicResponsiveListItem.ts index 945cd703..b4a095a4 100644 --- a/src/parser/classes/MusicResponsiveListItem.ts +++ b/src/parser/classes/MusicResponsiveListItem.ts @@ -80,7 +80,9 @@ class MusicResponsiveListItem extends YTNode { this.endpoint = data.navigationEndpoint ? new NavigationEndpoint(data.navigationEndpoint) : null; - switch (this.endpoint?.browse?.page_type) { + const page_type = this.endpoint?.payload?.browseEndpointContextSupportedConfigs?.browseEndpointContextMusicConfig?.pageType; + + switch (page_type) { case 'MUSIC_PAGE_TYPE_ALBUM': this.item_type = 'album'; this.#parseAlbum(); @@ -139,7 +141,7 @@ class MusicResponsiveListItem extends YTNode { } #parseSong() { - this.id = this.#playlist_item_data.video_id || this.endpoint?.watch?.video_id; + this.id = this.#playlist_item_data.video_id || this.endpoint?.payload?.videoId; this.title = this.#flex_columns[0].key('title').instanceof(Text).toString(); const duration_text = @@ -151,21 +153,21 @@ class MusicResponsiveListItem extends YTNode { seconds: timeToSeconds(duration_text) }); - const album = this.#flex_columns[1].key('title').instanceof(Text).runs?.find((run) => Reflect.get(run, 'endpoint')?.browse?.id.startsWith('MPR')) as TextRun || - this.#flex_columns[2]?.key('title').instanceof(Text).runs?.find((run) => Reflect.get(run, 'endpoint')?.browse?.id.startsWith('MPR')) as TextRun; + const album = this.#flex_columns[1].key('title').instanceof(Text).runs?.find((run) => Reflect.get(run, 'endpoint')?.payload?.browseId.startsWith('MPR')) as TextRun || + this.#flex_columns[2]?.key('title').instanceof(Text).runs?.find((run) => Reflect.get(run, 'endpoint')?.payload?.browseId.startsWith('MPR')) as TextRun; if (album) { this.album = { - id: album.endpoint?.browse?.id, + id: album.endpoint?.payload?.browseId, name: album.text, endpoint: album.endpoint }; } - const artists = this.#flex_columns[1].key('title').instanceof(Text).runs?.filter((run) => Reflect.get(run, 'endpoint')?.browse?.id.startsWith('UC')) as TextRun[]; + const artists = this.#flex_columns[1].key('title').instanceof(Text).runs?.filter((run) => Reflect.get(run, 'endpoint')?.payload?.browseId.startsWith('UC')) as TextRun[]; if (artists) { this.artists = artists.map((artist) => ({ name: artist.text, - channel_id: artist.endpoint?.browse?.id, + channel_id: artist.endpoint?.payload?.browseId, endpoint: artist.endpoint })); } @@ -176,11 +178,11 @@ class MusicResponsiveListItem extends YTNode { this.title = this.#flex_columns[0].key('title').instanceof(Text).toString(); this.views = this.#flex_columns[1].key('title').instanceof(Text).runs?.find((run) => run.text.match(/(.*?) views/))?.text; - const authors = this.#flex_columns[1].key('title').instanceof(Text).runs?.filter((run) => Reflect.get(run, 'endpoint')?.browse?.id.startsWith('UC')) as TextRun[]; + const authors = this.#flex_columns[1].key('title').instanceof(Text).runs?.filter((run) => Reflect.get(run, 'endpoint')?.payload?.browseId.startsWith('UC')) as TextRun[]; if (authors) { this.authors = authors.map((author) => ({ name: author.text, - channel_id: author.endpoint?.browse?.id, + channel_id: author.endpoint?.payload?.browseId, endpoint: author.endpoint })); } @@ -194,7 +196,7 @@ class MusicResponsiveListItem extends YTNode { } #parseArtist() { - this.id = this.endpoint?.browse?.id; + this.id = this.endpoint?.payload?.browseId; this.name = this.#flex_columns[0].key('title').instanceof(Text).toString(); this.subtitle = this.#flex_columns[1].key('title').instanceof(Text); this.subscribers = this.subtitle.runs?.find((run) => (/^(\d*\.)?\d+[M|K]? subscribers?$/i).test(run.text))?.text || ''; @@ -207,13 +209,13 @@ class MusicResponsiveListItem extends YTNode { } #parseAlbum() { - this.id = this.endpoint?.browse?.id; + this.id = this.endpoint?.payload?.browseId; this.title = this.#flex_columns[0].key('title').instanceof(Text).toString(); - const author = this.#flex_columns[1].key('title').instanceof(Text).runs?.find((run) => Reflect.get(run, 'endpoint')?.browse?.id.startsWith('UC')) as TextRun; + const author = this.#flex_columns[1].key('title').instanceof(Text).runs?.find((run) => Reflect.get(run, 'endpoint')?.payload?.browseId.startsWith('UC')) as TextRun; author && (this.author = { name: author.text, - channel_id: author.endpoint?.browse?.id, + channel_id: author.endpoint?.payload?.browseId, endpoint: author.endpoint }); @@ -221,7 +223,7 @@ class MusicResponsiveListItem extends YTNode { } #parsePlaylist() { - this.id = this.endpoint?.browse?.id; + this.id = this.endpoint?.payload?.browseId; this.title = this.#flex_columns[0].key('title').instanceof(Text).toString(); const item_count_run = this.#flex_columns[1].key('title') @@ -229,12 +231,12 @@ class MusicResponsiveListItem extends YTNode { this.item_count = item_count_run ? item_count_run.text : undefined; - const author = this.#flex_columns[1].key('title').instanceof(Text).runs?.find((run) => Reflect.get(run, 'endpoint')?.browse?.id.startsWith('UC')) as TextRun; + const author = this.#flex_columns[1].key('title').instanceof(Text).runs?.find((run) => Reflect.get(run, 'endpoint')?.payload?.browseId.startsWith('UC')) as TextRun; if (author) { this.author = { name: author.text, - channel_id: author.endpoint?.browse?.id, + channel_id: author.endpoint?.payload?.browseId, endpoint: author.endpoint }; } diff --git a/src/parser/classes/MusicSideAlignedItem.ts b/src/parser/classes/MusicSideAlignedItem.ts index 601645d8..a60b19c8 100644 --- a/src/parser/classes/MusicSideAlignedItem.ts +++ b/src/parser/classes/MusicSideAlignedItem.ts @@ -6,6 +6,7 @@ class MusicSideAlignedItem extends YTNode { static type = 'MusicSideAlignedItem'; start_items?; + end_items?; constructor(data: any) { super(); @@ -13,6 +14,10 @@ class MusicSideAlignedItem extends YTNode { if (data.startItems) { this.start_items = Parser.parseArray(data.startItems); } + + if (data.endItems) { + this.end_items = Parser.parseArray(data.endItems); + } } } diff --git a/src/parser/classes/MusicTwoRowItem.ts b/src/parser/classes/MusicTwoRowItem.ts index 1848db27..755c0ac8 100644 --- a/src/parser/classes/MusicTwoRowItem.ts +++ b/src/parser/classes/MusicTwoRowItem.ts @@ -48,13 +48,15 @@ class MusicTwoRowItem extends YTNode { this.endpoint = new NavigationEndpoint(data.navigationEndpoint); this.id = - this.endpoint?.browse?.id || - this.endpoint?.watch?.video_id; + this.endpoint?.payload?.browseId || + this.endpoint?.payload?.videoId; this.subtitle = new Text(data.subtitle); this.badges = Parser.parse(data.subtitleBadges); - switch (this.endpoint?.browse?.page_type) { + const page_type = this.endpoint?.payload?.browseEndpointContextSupportedConfigs?.browseEndpointContextMusicConfig?.pageType; + + switch (page_type) { case 'MUSIC_PAGE_TYPE_ARTIST': this.item_type = 'artist'; break; @@ -65,7 +67,7 @@ class MusicTwoRowItem extends YTNode { this.item_type = 'album'; break; default: - if (this.endpoint?.watch_playlist) { + if (this.endpoint?.metadata?.api_url === '/next') { this.item_type = 'endpoint'; } else if (this.subtitle.runs?.[0]) { if (this.subtitle.runs[0].text !== 'Song') { @@ -87,11 +89,11 @@ class MusicTwoRowItem extends YTNode { const item_count_run = this.subtitle.runs?.find((run) => run.text.match(/\d+ songs|song/)); this.item_count = item_count_run ? (item_count_run as TextRun).text : null; } else if (this.item_type == 'album') { - const artists = this.subtitle.runs?.filter((run: any) => run.endpoint?.browse?.id.startsWith('UC')); + const artists = this.subtitle.runs?.filter((run: any) => run.endpoint?.payload?.browseId.startsWith('UC')); if (artists) { this.artists = artists.map((artist: any) => ({ name: artist.text, - channel_id: artist.endpoint.browse.id, + channel_id: artist.endpoint?.payload?.browseId, endpoint: artist.endpoint })); } @@ -101,20 +103,20 @@ class MusicTwoRowItem extends YTNode { } else if (this.item_type == 'video') { this.views = this?.subtitle.runs?.find((run) => run?.text.match(/(.*?) views/))?.text || 'N/A'; - const author = this.subtitle.runs?.find((run: any) => run.endpoint?.browse?.id?.startsWith('UC')); + const author = this.subtitle.runs?.find((run: any) => run.endpoint?.payload?.browseId?.startsWith('UC')); if (author) { this.author = { name: (author as TextRun)?.text, - channel_id: (author as TextRun)?.endpoint?.browse?.id, + channel_id: (author as TextRun)?.endpoint?.payload?.browseId, endpoint: (author as TextRun)?.endpoint }; } } else if (this.item_type == 'song') { - const artists = this.subtitle.runs?.filter((run: any) => run.endpoint?.browse?.id.startsWith('UC')); + const artists = this.subtitle.runs?.filter((run: any) => run.endpoint?.payload?.browseId.startsWith('UC')); if (artists) { this.artists = artists.map((artist: any) => ({ name: (artist as TextRun)?.text, - channel_id: (artist as TextRun)?.endpoint?.browse?.id, + channel_id: (artist as TextRun)?.endpoint?.payload?.browseId, endpoint: (artist as TextRun)?.endpoint })); } diff --git a/src/parser/classes/NavigationEndpoint.ts b/src/parser/classes/NavigationEndpoint.ts index a9635de7..7063ffb4 100644 --- a/src/parser/classes/NavigationEndpoint.ts +++ b/src/parser/classes/NavigationEndpoint.ts @@ -1,7 +1,7 @@ -// TODO: refactor this -import { YTNode } from '../helpers'; import Parser, { ParsedResponse } from '../index'; import Actions, { ActionsResponse } from '../../core/Actions'; +import { YTNode } from '../helpers'; + import CreatePlaylistDialog from './CreatePlaylistDialog'; class NavigationEndpoint extends YTNode { @@ -14,34 +14,9 @@ class NavigationEndpoint extends YTNode { url?: string; api_url?: string; page_type?: string; - send_post?: boolean; // TODO: is this a boolean? + send_post?: boolean; }; - // TODO: these should be given proper types, currently infered - browse?: { - id: string, - params: string | null, - base_url: string | null, - page_type: string | null, - form_data?: {} - }; - watch; - search; - subscribe; - unsubscribe; - like; - perform_comment_action; - offline_video; - continuation; - feedback; - watch_playlist; - playlist_edit; - add_to_playlist; - create_playlist; - get_report_form; - live_chat_item_context_menu; - send_live_chat_vote; - constructor(data: any) { super(); @@ -85,150 +60,10 @@ class NavigationEndpoint extends YTNode { this.metadata.send_post = data.commandMetadata.webCommandMetadata.sendPost; } - if (data?.browseEndpoint) { - const configs = data?.browseEndpoint?.browseEndpointContextSupportedConfigs?.browseEndpointContextMusicConfig; - this.browse = { - id: data?.browseEndpoint?.browseId || null, - params: data?.browseEndpoint.params || null, - base_url: data?.browseEndpoint?.canonicalBaseUrl || null, - page_type: configs?.pageType || null - }; - } - - if (data?.watchEndpoint) { - const configs = data?.watchEndpoint?.watchEndpointMusicSupportedConfigs?.watchEndpointMusicConfig; - this.watch = { - video_id: data?.watchEndpoint?.videoId, - playlist_id: data?.watchEndpoint.playlistId || null, - params: data?.watchEndpoint.params || null, - index: data?.watchEndpoint.index || null, - supported_onesie_config: data?.watchEndpoint?.watchEndpointSupportedOnesieConfig, - music_video_type: configs?.musicVideoType || null - }; - } - - if (data?.searchEndpoint) { - this.search = { - query: data.searchEndpoint.query, - params: data.searchEndpoint.params - }; - } - - if (data?.subscribeEndpoint) { - this.subscribe = { - channel_ids: data.subscribeEndpoint.channelIds, - params: data.subscribeEndpoint.params - }; - } - - if (data?.unsubscribeEndpoint) { - this.unsubscribe = { - channel_ids: data.unsubscribeEndpoint.channelIds, - params: data.unsubscribeEndpoint.params - }; - } - - if (data?.likeEndpoint) { - this.like = { - status: data.likeEndpoint.status, - target: { - video_id: data.likeEndpoint.target.videoId, - playlist_id: data.likeEndpoint.target.playlistId - }, - params: - data.likeEndpoint?.removeLikeParams || - data.likeEndpoint?.likeParams || - data.likeEndpoint?.dislikeParams - }; - } - - if (data?.performCommentActionEndpoint) { - this.perform_comment_action = { - action: data?.performCommentActionEndpoint.action - }; - } - - if (data?.offlineVideoEndpoint) { - this.offline_video = { - video_id: data.offlineVideoEndpoint.videoId, - on_add_command: { - get_download_action: { - video_id: data.offlineVideoEndpoint.videoId, - params: data.offlineVideoEndpoint.onAddCommand.getDownloadActionCommand.params - } - } - }; - } - - if (data?.continuationCommand) { - this.continuation = { - request: data?.continuationCommand?.request || null, - token: data?.continuationCommand?.token || null - }; - } - - if (data?.feedbackEndpoint) { - this.feedback = { - token: data.feedbackEndpoint.feedbackToken - }; - } - - if (data?.watchPlaylistEndpoint) { - this.watch_playlist = { - playlist_id: data.watchPlaylistEndpoint?.playlistId, - params: data.watchPlaylistEndpoint?.params || null - }; - } - - if (data?.playlistEditEndpoint) { - this.playlist_edit = { - playlist_id: data.playlistEditEndpoint.playlistId, - actions: data.playlistEditEndpoint.actions.map((item: any) => ({ - action: item.action, - removed_video_id: item.removedVideoId - })) - }; - } - - if (data?.addToPlaylistEndpoint) { - this.add_to_playlist = { - video_id: data.addToPlaylistEndpoint.videoId - }; - } - - if (data?.addToPlaylistServiceEndpoint) { - this.add_to_playlist = { - video_id: data.addToPlaylistServiceEndpoint.videoId - }; - } - if (data?.createPlaylistEndpoint) { if (data?.createPlaylistEndpoint.createPlaylistDialog) { this.dialog = Parser.parseItem(data?.createPlaylistEndpoint.createPlaylistDialog, CreatePlaylistDialog); } - this.create_playlist = { - // Nothing to put here - data.createPlaylistEndpoint has only one prop `createPlaylistDialog` - // Which was already parsed and referred to by `this.dialog`. But still useful to have this as - // A quick indicator of what the endpoint does. - }; - } - - if (data?.getReportFormEndpoint) { - this.get_report_form = { - params: data.getReportFormEndpoint.params - }; - } - - if (data?.liveChatItemContextMenuEndpoint) { - this.live_chat_item_context_menu = { - params: data?.liveChatItemContextMenuEndpoint?.params - }; - } - - if (data?.sendLiveChatVoteEndpoint) { - this.send_live_chat_vote = { - params: data.sendLiveChatVoteEndpoint.params - }; } } @@ -248,72 +83,15 @@ class NavigationEndpoint extends YTNode { } } - callTest(actions: Actions, args: { [ key: string ]: any; parse: true }): Promise; - callTest(actions: Actions, args?: { [ key: string ]: any; parse?: false }): Promise; - callTest(actions: Actions, args?: { [ key: string ]: any; parse?: boolean }): Promise { + call(actions: Actions, args: { [ key: string ]: any; parse: true }): Promise; + call(actions: Actions, args?: { [ key: string ]: any; parse?: false }): Promise; + call(actions: Actions, args?: { [ key: string ]: any; parse?: boolean }): Promise { if (!actions) throw new Error('An active caller must be provided'); if (!this.metadata.api_url) throw new Error('Expected an api_url, but none was found, this is a bug.'); return actions.execute(this.metadata.api_url, { ...this.payload, ...args }); } - - // TODO: replace client with an enum or something - async #call(actions: Actions, client?: string) { - if (!actions) - throw new Error('An active caller must be provided'); - - if (this.continuation) { - switch (this.continuation.request) { - case 'CONTINUATION_REQUEST_TYPE_BROWSE': { - return await actions.browse(this.continuation.token, { is_ctoken: true }); - } - case 'CONTINUATION_REQUEST_TYPE_SEARCH': { - return await actions.search({ ctoken: this.continuation.token }); - } - case 'CONTINUATION_REQUEST_TYPE_WATCH_NEXT': { - return await actions.next({ ctoken: this.continuation.token }); - } - default: - throw new Error(`${this.continuation.request} not implemented`); - } - } - - if (this.search) { - return await actions.search({ query: this.search.query, params: this.search.params, client }); - } - - if (this.browse) { - return await actions.browse(this.browse.id, { ...this.browse, client }); - } - - if (this.like) { - if (!this.metadata.api_url) - throw new Error('Like endpoint requires an api_url, but was not parsed from the response.'); - const response = await actions.engage(this.metadata.api_url, { video_id: this.like.target.video_id, params: this.like.params }); - return response; - } - - if (this.live_chat_item_context_menu) { - if (!this.metadata.api_url) - throw new Error('Live Chat Item Context Menu endpoint requires an api_url, but was not parsed from the response.'); - const response = await actions.livechat(this.metadata.api_url, { - params: this.live_chat_item_context_menu.params - }); - return response; - } - } - - async call(actions: Actions, client: string | undefined, parse: true) : Promise; - async call(actions: Actions, client?: string, parse?: false) : Promise; - async call(actions: Actions, client?: string, parse?: boolean): Promise { - const result = await this.#call(actions, client); - - if (parse && result) - return Parser.parseResponse(result.data); - - return result; - } } export default NavigationEndpoint; \ No newline at end of file diff --git a/src/parser/classes/PlaylistPanelVideo.ts b/src/parser/classes/PlaylistPanelVideo.ts index 90ce6a55..b10429c6 100644 --- a/src/parser/classes/PlaylistPanelVideo.ts +++ b/src/parser/classes/PlaylistPanelVideo.ts @@ -54,14 +54,14 @@ class PlaylistPanelVideo extends YTNode { seconds: timeToSeconds(new Text(data.lengthText).toString()) }; - const album = new Text(data.longBylineText).runs?.find((run: any) => run.endpoint?.browse?.id.startsWith('MPR')); - const artists = new Text(data.longBylineText).runs?.filter((run: any) => run.endpoint?.browse?.id.startsWith('UC')); + const album = new Text(data.longBylineText).runs?.find((run: any) => run.endpoint?.payload?.browseId?.startsWith('MPR')); + const artists = new Text(data.longBylineText).runs?.filter((run: any) => run.endpoint?.payload?.browseId?.startsWith('UC')); this.author = new Text(data.shortBylineText).toString(); if (album) { this.album = { - id: (album as TextRun).endpoint?.browse?.id, + id: (album as TextRun).endpoint?.payload?.browseId, name: (album as TextRun).text, year: new Text(data.longBylineText).runs?.slice(-1)[0].text, endpoint: (album as TextRun).endpoint @@ -71,7 +71,7 @@ class PlaylistPanelVideo extends YTNode { if (artists) { this.artists = artists.map((artist) => ({ name: (artist as TextRun).text, - channel_id: (artist as TextRun).endpoint?.browse?.id, + channel_id: (artist as TextRun).endpoint?.payload?.browseId, endpoint: (artist as TextRun).endpoint })); } diff --git a/src/parser/classes/comments/Comment.ts b/src/parser/classes/comments/Comment.ts index b2121b0a..355f1e8b 100644 --- a/src/parser/classes/comments/Comment.ts +++ b/src/parser/classes/comments/Comment.ts @@ -82,7 +82,7 @@ class Comment extends YTNode { if (button.is_toggled) throw new InnertubeError('This comment is already liked', { comment_id: this.comment_id }); - const response = await button.endpoint.callTest(this.#actions, { parse: false }); + const response = await button.endpoint.call(this.#actions, { parse: false }); return response; } @@ -98,7 +98,7 @@ class Comment extends YTNode { if (button.is_toggled) throw new InnertubeError('This comment is already disliked', { comment_id: this.comment_id }); - const response = await button.endpoint.callTest(this.#actions, { parse: false }); + const response = await button.endpoint.call(this.#actions, { parse: false }); return response; } @@ -125,7 +125,7 @@ class Comment extends YTNode { commentText: text }; - const response = await dialog_button.endpoint.callTest(this.#actions, payload); + const response = await dialog_button.endpoint.call(this.#actions, payload); return response; } diff --git a/src/parser/classes/comments/CommentThread.ts b/src/parser/classes/comments/CommentThread.ts index d000acaa..001aac4a 100644 --- a/src/parser/classes/comments/CommentThread.ts +++ b/src/parser/classes/comments/CommentThread.ts @@ -35,7 +35,7 @@ class CommentThread extends YTNode { throw new InnertubeError('This comment has no replies.', { comment_id: this.comment?.comment_id }); const continuation = this.#replies.key('contents').parsed().array().get({ type: 'ContinuationItem' })?.as(ContinuationItem); - const response = await continuation?.endpoint.callTest(this.#actions, { parse: true }); + const response = await continuation?.endpoint.call(this.#actions, { parse: true }); this.replies = response?.on_response_received_endpoints_memo?.getType(Comment).map((comment) => { comment.setActions(this.#actions); @@ -60,7 +60,7 @@ class CommentThread extends YTNode { if (!this.#actions) throw new InnertubeError('Actions not set for this CommentThread.'); - const response = await this.#continuation.button?.item().key('endpoint').nodeOfType(NavigationEndpoint).callTest(this.#actions, { parse: true }); + const response = await this.#continuation.button?.item().key('endpoint').nodeOfType(NavigationEndpoint).call(this.#actions, { parse: true }); this.replies = response?.on_response_received_endpoints_memo.getType(Comment).map((comment) => { comment.setActions(this.#actions); diff --git a/src/parser/classes/menus/MusicMultiSelectMenuItem.ts b/src/parser/classes/menus/MusicMultiSelectMenuItem.ts index 299d2757..a705ad50 100644 --- a/src/parser/classes/menus/MusicMultiSelectMenuItem.ts +++ b/src/parser/classes/menus/MusicMultiSelectMenuItem.ts @@ -8,7 +8,7 @@ class MusicMultiSelectMenuItem extends YTNode { title: string; form_item_entity_key: string; selected_icon_type: string; - endpoint?: NavigationEndpoint; + endpoint?: NavigationEndpoint | null; selected: boolean; constructor(data: any) { @@ -17,19 +17,7 @@ class MusicMultiSelectMenuItem extends YTNode { this.title = new Text(data.title).text; this.form_item_entity_key = data.formItemEntityKey; this.selected_icon_type = data.selectedIcon?.iconType || null; - const command = data.selectedCommand?.commandExecutorCommand?.commands?.find((command: any) => command.musicBrowseFormBinderCommand?.browseEndpoint); - if (command) { - /** - * At this point, endpoint will still be missing `form_data` field which is required for - * selection to take effect. This can only be obtained from the response data which - * we don't have here. We shall delegate this task back to `Parser`. - */ - this.endpoint = new NavigationEndpoint(command.musicBrowseFormBinderCommand); - } - /** - * Inferring selected state from existence of endpoint. `Parser` shall - * update this with the definitive value obtained from response data. - */ + this.endpoint = data.selectedCommand ? new NavigationEndpoint(data.selectedCommand) : null; this.selected = !!this.endpoint; } } diff --git a/src/parser/classes/misc/Author.ts b/src/parser/classes/misc/Author.ts index 2b792c23..27109092 100644 --- a/src/parser/classes/misc/Author.ts +++ b/src/parser/classes/misc/Author.ts @@ -21,8 +21,8 @@ class Author { this.#nav_text = new NavigatableText(item); this.id = - (this.#nav_text.runs?.[0] as TextRun)?.endpoint?.browse?.id || - this.#nav_text?.endpoint?.browse?.id || 'N/A'; + (this.#nav_text.runs?.[0] as TextRun)?.endpoint?.payload?.browseId || + this.#nav_text?.endpoint?.payload?.browseId || 'N/A'; this.name = this.#nav_text.text || 'N/A'; this.thumbnails = thumbs ? Thumbnail.fromResponse(thumbs) : []; @@ -32,9 +32,9 @@ class Author { this.is_verified_artist = this.badges?.some((badge: any) => badge.style == 'BADGE_STYLE_TYPE_VERIFIED_ARTIST') || null; this.url = - (this.#nav_text?.runs?.[0] as TextRun)?.endpoint?.browse && - `${Constants.URLS.YT_BASE}${(this.#nav_text?.runs?.[0] as TextRun)?.endpoint?.browse?.base_url || `/u/${(this.#nav_text?.runs?.[0] as TextRun)?.endpoint?.browse?.id}`}` || - `${Constants.URLS.YT_BASE}${this.#nav_text?.endpoint?.browse?.base_url || `/u/${this.#nav_text?.endpoint?.browse?.id}`}` || + (this.#nav_text?.runs?.[0] as TextRun)?.endpoint?.metadata?.api_url === '/browse' && + `${Constants.URLS.YT_BASE}${(this.#nav_text?.runs?.[0] as TextRun)?.endpoint?.payload?.canonicalBaseUrl || `/u/${(this.#nav_text?.runs?.[0] as TextRun)?.endpoint?.payload?.browseId}`}` || + `${Constants.URLS.YT_BASE}${this.#nav_text?.endpoint?.payload?.canonicalBaseUrl || `/u/${this.#nav_text?.endpoint?.payload?.browseId}`}` || null; } diff --git a/src/parser/index.ts b/src/parser/index.ts index db44c0b9..bb846580 100644 --- a/src/parser/index.ts +++ b/src/parser/index.ts @@ -50,7 +50,9 @@ export class SectionListContinuation extends YTNode { constructor(data: any) { super(); this.contents = Parser.parse(data.contents, true); - this.continuation = data.continuations?.[0].nextContinuationData.continuation || null; + this.continuation = + data.continuations?.[0]?.nextContinuationData?.continuation || + data.continuations?.[0]?.reloadContinuationData?.continuation || null; } } @@ -211,11 +213,11 @@ export default class Parser { */ static parseResponse(data: any) { // Memoize the response objects by classname + this.#createMemo(); // TODO: is this parseItem? const contents = Parser.parse(data.contents); const contents_memo = this.#getMemo(); - // End of memoization this.#clearMemo(); this.#createMemo(); @@ -245,6 +247,17 @@ export default class Parser { const live_chat_item_context_menu_supported_renderers_memo = this.#getMemo(); this.#clearMemo(); + this.#createMemo(); + const header = data.header ? Parser.parse(data.header) : null; + const header_memo = this.#getMemo(); + this.#clearMemo(); + + this.#createMemo(); + const sidebar = data.sidebar ? Parser.parseItem(data.sidebar) : null; + const sidebar_memo = this.#getMemo(); + this.#clearMemo(); + + this.applyMutations(contents_memo, data.frameworkUpdates?.entityBatchUpdate?.mutations); return { @@ -252,6 +265,10 @@ export default class Parser { actions_memo, contents, contents_memo, + header, + header_memo, + sidebar, + sidebar_memo, live_chat_item_context_menu_supported_renderers, live_chat_item_context_menu_supported_renderers_memo, on_response_received_actions, @@ -263,9 +280,7 @@ export default class Parser { continuation: data.continuation ? Parser.parseC(data.continuation) : null, continuation_contents: data.continuationContents ? Parser.parseLC(data.continuationContents) : null, metadata: Parser.parse(data.metadata), - header: Parser.parse(data.header), microformat: data.microformat ? Parser.parseItem(data.microformat) : null, - sidebar: Parser.parseItem(data.sidebar), overlay: Parser.parseItem(data.overlay), refinements: data.refinements || null, estimated_results: data.estimatedResults ? parseInt(data.estimatedResults) : null, @@ -390,8 +405,8 @@ export default class Parser { throw new ParsingError('Expected array but got a single item'); } - static parse(data: any, requireArray: true, validTypes?: YTNodeConstructor | YTNodeConstructor[]) : ObservedArray | null; - static parse(data: any, requireArray?: false | undefined, validTypes?: YTNodeConstructor | YTNodeConstructor[]) : SuperParsedResult; + static parse(data: any, requireArray: true, validTypes?: YTNodeConstructor | YTNodeConstructor[]): ObservedArray | null; + static parse(data: any, requireArray?: false | undefined, validTypes?: YTNodeConstructor | YTNodeConstructor[]): SuperParsedResult; static parse(data: any, requireArray?: boolean, validTypes?: YTNodeConstructor | YTNodeConstructor[]) { if (!data) return null; @@ -417,8 +432,9 @@ export default class Parser { static applyMutations(memo: Memo, mutations: Array) { // Apply mutations to MusicMultiSelectMenuItems - const musicMultiSelectMenuItems = memo.getType(MusicMultiSelectMenuItem); - if (musicMultiSelectMenuItems.length > 0 && !mutations) { + const music_multi_select_menu_items = memo.getType(MusicMultiSelectMenuItem); + + if (music_multi_select_menu_items.length > 0 && !mutations) { console.warn( new InnertubeError( 'Mutation data required for processing MusicMultiSelectMenuItems, but none found.\n' + @@ -426,26 +442,25 @@ export default class Parser { ) ); } else { - const missingOrInvalidMutations = []; - for (const menuItem of musicMultiSelectMenuItems) { - const mutation = mutations.find((mutation) => mutation.payload?.musicFormBooleanChoice?.id === menuItem.form_item_entity_key); + const missing_or_invalid_mutations = []; + + for (const menu_item of music_multi_select_menu_items) { + const mutation = mutations + .find((mutation) => mutation.payload?.musicFormBooleanChoice?.id === menu_item.form_item_entity_key); + const choice = mutation?.payload.musicFormBooleanChoice; + if (choice?.selected !== undefined && choice?.opaqueToken) { - menuItem.selected = choice.selected; - if (menuItem.endpoint?.browse) { - menuItem.endpoint.browse.form_data = { - selectedValues: [ choice.opaqueToken ] - }; - } + menu_item.selected = choice.selected; } else { - missingOrInvalidMutations.push(`'${menuItem.title}'`); + missing_or_invalid_mutations.push(`'${menu_item.title}'`); } } - if (missingOrInvalidMutations.length > 0) { + if (missing_or_invalid_mutations.length > 0) { console.warn( new InnertubeError( - `Mutation data missing or invalid for ${missingOrInvalidMutations.length} out of ${musicMultiSelectMenuItems.length} MusicMultiSelectMenuItems. ` + - `The titles of the failed items are: ${missingOrInvalidMutations.join(', ')}.\n` + + `Mutation data missing or invalid for ${missing_or_invalid_mutations.length} out of ${music_multi_select_menu_items.length} MusicMultiSelectMenuItems. ` + + `The titles of the failed items are: ${missing_or_invalid_mutations.join(', ')}.\n` + `This is a bug, please report it at ${package_json.bugs.url}` ) ); diff --git a/src/parser/youtube/AccountInfo.ts b/src/parser/youtube/AccountInfo.ts index d4d63ab4..fb252373 100644 --- a/src/parser/youtube/AccountInfo.ts +++ b/src/parser/youtube/AccountInfo.ts @@ -1,5 +1,5 @@ import Parser, { ParsedResponse } from '..'; -import { AxioslikeResponse } from '../../core/Actions'; +import { ApiResponse } from '../../core/Actions'; import AccountSectionList from '../classes/AccountSectionList'; import AccountItemSection from '../classes/AccountItemSection'; @@ -11,7 +11,7 @@ class AccountInfo { contents: AccountItemSection | null; footers: AccountChannel | null; - constructor(response: AxioslikeResponse) { + constructor(response: ApiResponse) { this.#page = Parser.parseResponse(response.data); const account_section_list = this.#page.contents.array().as(AccountSectionList)[0]; diff --git a/src/parser/youtube/Analytics.ts b/src/parser/youtube/Analytics.ts index d40ee5b9..e149e905 100644 --- a/src/parser/youtube/Analytics.ts +++ b/src/parser/youtube/Analytics.ts @@ -1,12 +1,12 @@ import Parser, { ParsedResponse } from '..'; -import { AxioslikeResponse } from '../../core/Actions'; +import { ApiResponse } from '../../core/Actions'; import Element from '../classes/Element'; class Analytics { #page; sections; - constructor(response: AxioslikeResponse) { + constructor(response: ApiResponse) { this.#page = Parser.parseResponse(response.data); this.sections = this.#page.contents_memo?.get('Element') ?.map((el) => el.as(Element).model?.item()); diff --git a/src/parser/youtube/Channel.ts b/src/parser/youtube/Channel.ts index 46293457..9c490c50 100644 --- a/src/parser/youtube/Channel.ts +++ b/src/parser/youtube/Channel.ts @@ -16,13 +16,13 @@ class Channel extends TabbedFeed { constructor(actions: Actions, data: any, already_parsed = false) { super(actions, data, already_parsed); - this.header = this.page.header.item().as(C4TabbedHeader); + this.header = this.page.header?.item().as(C4TabbedHeader); const metadata = this.page.metadata.item().as(ChannelMetadata); const microformat = this.page.microformat?.as(MicroformatData); this.metadata = { ...metadata, ...(microformat || {}) }; - this.sponsor_button = this.header.sponsor_button; - this.subscribe_button = this.header.subscribe_button; + this.sponsor_button = this.header?.sponsor_button; + this.subscribe_button = this.header?.subscribe_button; const tab = this.page.contents.item().key('tabs').parsed().array().filterType(Tab).get({ selected: true }); diff --git a/src/parser/youtube/Comments.ts b/src/parser/youtube/Comments.ts index f74f36bc..46c9a322 100644 --- a/src/parser/youtube/Comments.ts +++ b/src/parser/youtube/Comments.ts @@ -40,19 +40,18 @@ class Comments { /** * Creates a top-level comment. + * @param text - Comment text. */ async createComment(text: string): Promise { if (!this.header) - throw new InnertubeError('Page header is missing.'); + throw new InnertubeError('Page header is missing. Cannot create comment.'); - const button = this.header.create_renderer?.as(CommentSimplebox).submit_button.item().as(Button); + const button = this.header.create_renderer?.as(CommentSimplebox).submit_button?.item().as(Button); if (!button) - throw new InnertubeError('Could not find target button.'); + throw new InnertubeError('Could not find target button. You are probably not logged in.'); - const response = await button.endpoint.callTest(this.#actions, { - commentText: text - }); + const response = await button.endpoint.call(this.#actions, { commentText: text }); return response; } @@ -64,13 +63,13 @@ class Comments { if (!this.#continuation) throw new InnertubeError('Continuation not found'); - const data = await this.#continuation.endpoint.callTest(this.#actions, { parse: true }); + const data = await this.#continuation.endpoint.call(this.#actions, { parse: true }); // Copy the previous page so we can keep the header. const page = Object.assign({}, this.#page); if (!page.on_response_received_endpoints || !data.on_response_received_endpoints) - throw new InnertubeError('Invalid reponse format, missing on_response_received_endpoints'); + throw new InnertubeError('Invalid reponse format, missing on_response_received_endpoints.'); // Remove previous items and append the continuation. page.on_response_received_endpoints.pop(); diff --git a/src/parser/youtube/ItemMenu.ts b/src/parser/youtube/ItemMenu.ts index f73d4581..5e8c014c 100644 --- a/src/parser/youtube/ItemMenu.ts +++ b/src/parser/youtube/ItemMenu.ts @@ -48,7 +48,7 @@ class ItemMenu { endpoint = button.as(MenuServiceItem).endpoint; } - const response = await endpoint.callTest(this.#actions, { parse: true }); + const response = await endpoint.call(this.#actions, { parse: true }); return response; } diff --git a/src/parser/youtube/Library.ts b/src/parser/youtube/Library.ts index b6c70180..6b91c505 100644 --- a/src/parser/youtube/Library.ts +++ b/src/parser/youtube/Library.ts @@ -1,5 +1,5 @@ import Parser, { ParsedResponse } from '..'; -import Actions, { AxioslikeResponse } from '../../core/Actions'; +import Actions, { ApiResponse } from '../../core/Actions'; import { InnertubeError } from '../../utils/Utils'; import Feed from '../../core/Feed'; @@ -25,7 +25,7 @@ class Library { profile; sections; - constructor(response: AxioslikeResponse, actions: Actions) { + constructor(response: ApiResponse, actions: Actions) { this.#actions = actions; this.#page = Parser.parseResponse(response); @@ -66,7 +66,7 @@ class Library { if (!button) throw new InnertubeError('Did not find target button.'); - const page = await button.as(Button).endpoint.callTest(this.#actions, { parse: true }); + const page = await button.as(Button).endpoint.call(this.#actions, { parse: true }); switch (shelf.icon_type) { case 'LIKE': diff --git a/src/parser/youtube/LiveChat.ts b/src/parser/youtube/LiveChat.ts index bfc61877..9d737aed 100644 --- a/src/parser/youtube/LiveChat.ts +++ b/src/parser/youtube/LiveChat.ts @@ -192,7 +192,7 @@ class LiveChat extends EventEmitter { if (!item.menu_endpoint) throw new InnertubeError('This item does not have a menu.', item); - const response = await item.menu_endpoint.call(this.#actions, undefined, true); + const response = await item.menu_endpoint.call(this.#actions, { parse: true }); if (!response) throw new InnertubeError('Could not retrieve item menu.', item); @@ -204,7 +204,7 @@ class LiveChat extends EventEmitter { * Equivalent to "clicking" a button. */ async selectButton(button: Button): Promise { - const response = await button.endpoint.callTest(this.#actions, { parse: true }); + const response = await button.endpoint.call(this.#actions, { parse: true }); return response; } diff --git a/src/parser/youtube/NotificationsMenu.ts b/src/parser/youtube/NotificationsMenu.ts index 3b5fdc88..34fcfcdb 100644 --- a/src/parser/youtube/NotificationsMenu.ts +++ b/src/parser/youtube/NotificationsMenu.ts @@ -1,5 +1,5 @@ import Parser from '..'; -import Actions, { AxioslikeResponse } from '../../core/Actions'; +import Actions, { ApiResponse } from '../../core/Actions'; import { InnertubeError } from '../../utils/Utils'; import Notification from '../classes/Notification'; @@ -13,7 +13,7 @@ class NotificationsMenu { header; contents; - constructor(actions: Actions, response: AxioslikeResponse) { + constructor(actions: Actions, response: ApiResponse) { this.#actions = actions; this.#page = Parser.parseResponse(response.data); @@ -27,7 +27,7 @@ class NotificationsMenu { if (!continuation) throw new InnertubeError('Continuation not found'); - const response = await continuation.endpoint.callTest(this.#actions, { parse: false }); + const response = await continuation.endpoint.call(this.#actions, { parse: false }); return new NotificationsMenu(this.#actions, response); } } diff --git a/src/parser/youtube/Playlist.ts b/src/parser/youtube/Playlist.ts index c925bb7d..9d9e574d 100644 --- a/src/parser/youtube/Playlist.ts +++ b/src/parser/youtube/Playlist.ts @@ -4,13 +4,14 @@ import Feed from '../../core/Feed'; import Thumbnail from '../classes/misc/Thumbnail'; import VideoOwner from '../classes/VideoOwner'; -import PlaylistSidebar from '../classes/PlaylistSidebar'; import PlaylistMetadata from '../classes/PlaylistMetadata'; import PlaylistSidebarPrimaryInfo from '../classes/PlaylistSidebarPrimaryInfo'; import PlaylistSidebarSecondaryInfo from '../classes/PlaylistSidebarSecondaryInfo'; import PlaylistVideoThumbnail from '../classes/PlaylistVideoThumbnail'; import PlaylistHeader from '../classes/PlaylistHeader'; +import { InnertubeError } from '../../utils/Utils'; + class Playlist extends Feed { info; menu; @@ -19,9 +20,12 @@ class Playlist extends Feed { constructor(actions: Actions, data: any, already_parsed = false) { super(actions, data, already_parsed); - const header = this.page.header.item().as(PlaylistHeader); - const primary_info = this.page.sidebar?.as(PlaylistSidebar).contents.array().firstOfType(PlaylistSidebarPrimaryInfo); - const secondary_info = this.page.sidebar?.as(PlaylistSidebar).contents.array().firstOfType(PlaylistSidebarSecondaryInfo); + const header = this.memo.getType(PlaylistHeader)?.[0]; + const primary_info = this.memo.getType(PlaylistSidebarPrimaryInfo)?.[0]; + const secondary_info = this.memo.getType(PlaylistSidebarSecondaryInfo)?.[0]; + + if (!primary_info && !secondary_info) + throw new InnertubeError('This playlist does not exist'); this.info = { ...this.page.metadata.item().as(PlaylistMetadata), @@ -31,14 +35,14 @@ class Playlist extends Feed { total_items: this.#getStat(0, primary_info), views: this.#getStat(1, primary_info), last_updated: this.#getStat(2, primary_info), - can_share: header.can_share, - can_delete: header.can_delete, - is_editable: header.is_editable, - privacy: header.privacy + can_share: header?.can_share, + can_delete: header?.can_delete, + is_editable: header?.is_editable, + privacy: header?.privacy } }; - this.menu = primary_info?.menu; + this.menu = primary_info?.menu.item(); this.endpoint = primary_info?.endpoint; } @@ -50,6 +54,11 @@ class Playlist extends Feed { get items() { return this.videos; } + + async getContinuation(): Promise { + const response = await this.getContinuationData(); + return new Playlist(this.actions, response); + } } export default Playlist; \ No newline at end of file diff --git a/src/parser/youtube/Search.ts b/src/parser/youtube/Search.ts index f24acff2..1f91908e 100644 --- a/src/parser/youtube/Search.ts +++ b/src/parser/youtube/Search.ts @@ -66,7 +66,7 @@ class Search extends Feed { throw new InnertubeError('Invalid refinement card!'); } - const page = await target_card.endpoint.call(this.actions, undefined, true); + const page = await target_card.endpoint.call(this.actions, { parse: true }); return new Search(this.actions, page, true); } diff --git a/src/parser/youtube/Settings.ts b/src/parser/youtube/Settings.ts index 0c86e744..f4651484 100644 --- a/src/parser/youtube/Settings.ts +++ b/src/parser/youtube/Settings.ts @@ -1,5 +1,5 @@ import Parser from '..'; -import Actions, { AxioslikeResponse } from '../../core/Actions'; +import Actions, { ApiResponse } from '../../core/Actions'; import { InnertubeError } from '../../utils/Utils'; import Tab from '../classes/Tab'; @@ -20,7 +20,7 @@ class Settings { introduction: PageIntroduction | null | undefined; sections; - constructor(actions: Actions, response: AxioslikeResponse) { + constructor(actions: Actions, response: ApiResponse) { this.#actions = actions; this.#page = Parser.parseResponse(response.data); @@ -53,7 +53,7 @@ class Settings { if (!item) throw new InnertubeError(`Item "${name}" not found`, { available_items: this.sidebar_items }); - const response = await item.endpoint.callTest(this.#actions, { parse: false }); + const response = await item.endpoint.call(this.#actions, { parse: false }); return new Settings(this.#actions, response); } diff --git a/src/parser/youtube/TimeWatched.ts b/src/parser/youtube/TimeWatched.ts index 547fa616..b49d809c 100644 --- a/src/parser/youtube/TimeWatched.ts +++ b/src/parser/youtube/TimeWatched.ts @@ -1,5 +1,5 @@ import Parser, { ParsedResponse } from '..'; -import { AxioslikeResponse } from '../../core/Actions'; +import { ApiResponse } from '../../core/Actions'; import ItemSection from '../classes/ItemSection'; import SingleColumnBrowseResults from '../classes/SingleColumnBrowseResults'; @@ -11,7 +11,7 @@ class TimeWatched { #page; contents; - constructor(response: AxioslikeResponse) { + constructor(response: ApiResponse) { this.#page = Parser.parseResponse(response.data); const tab = this.#page.contents.item().as(SingleColumnBrowseResults).tabs.get({ selected: true }); diff --git a/src/parser/youtube/VideoInfo.ts b/src/parser/youtube/VideoInfo.ts index 9e81cee9..d7b89161 100644 --- a/src/parser/youtube/VideoInfo.ts +++ b/src/parser/youtube/VideoInfo.ts @@ -1,6 +1,6 @@ import Parser, { ParsedResponse } from '../index'; import Constants from '../../utils/Constants'; -import Actions, { AxioslikeResponse } from '../../core/Actions'; +import Actions, { ApiResponse } from '../../core/Actions'; import Player from '../../core/Player'; import TwoColumnWatchNextResults from '../classes/TwoColumnWatchNextResults'; @@ -92,7 +92,7 @@ class VideoInfo { * @param data - API response. * @param cpn - Client Playback Nonce */ - constructor(data: [AxioslikeResponse, AxioslikeResponse?], actions: Actions, player: Player, cpn: string) { + constructor(data: [ApiResponse, ApiResponse?], actions: Actions, player: Player, cpn: string) { this.#actions = actions; this.#player = player; this.#cpn = cpn; @@ -177,7 +177,7 @@ class VideoInfo { const filter = this.related_chip_cloud?.chips?.get({ text: name }); if (filter?.is_selected) return this; - const response = await filter?.endpoint?.call(this.#actions, undefined, true); + const response = await filter?.endpoint?.call(this.#actions, { parse: true }); const data = response?.on_response_received_endpoints?.get({ target_id: 'watch-next-feed' }); this.watch_next_feed = data?.contents; @@ -213,7 +213,7 @@ class VideoInfo { * Retrieves watch next feed continuation. */ async getWatchNextContinuation() { - const response = await this.#watch_next_continuation?.endpoint.call(this.#actions, undefined, true); + const response = await this.#watch_next_continuation?.endpoint.call(this.#actions, { parse: true }); const data = response?.on_response_received_endpoints?.get({ type: 'appendContinuationItemsAction' }); if (!data) diff --git a/src/parser/ytmusic/Album.ts b/src/parser/ytmusic/Album.ts index 1863338c..c2c76f90 100644 --- a/src/parser/ytmusic/Album.ts +++ b/src/parser/ytmusic/Album.ts @@ -1,5 +1,5 @@ import Parser, { ParsedResponse } from '../index'; -import Actions, { AxioslikeResponse } from '../../core/Actions'; +import Actions, { ApiResponse } from '../../core/Actions'; import MusicDetailHeader from '../classes/MusicDetailHeader'; import MicroformatData from '../classes/MicroformatData'; @@ -16,11 +16,11 @@ class Album { url: string | null; - constructor(response: AxioslikeResponse, actions: Actions) { + constructor(response: ApiResponse, actions: Actions) { this.#page = Parser.parseResponse(response.data); this.#actions = actions; - this.header = this.#page.header.item().as(MusicDetailHeader); + this.header = this.#page.header?.item().as(MusicDetailHeader); this.url = this.#page.microformat?.as(MicroformatData).url_canonical || null; this.contents = this.#page.contents_memo.get('MusicShelf')?.[0].as(MusicShelf).contents; diff --git a/src/parser/ytmusic/Artist.ts b/src/parser/ytmusic/Artist.ts index d8045fbb..49c1c97f 100644 --- a/src/parser/ytmusic/Artist.ts +++ b/src/parser/ytmusic/Artist.ts @@ -1,5 +1,5 @@ import Parser, { ParsedResponse } from '../index'; -import Actions, { AxioslikeResponse } from '../../core/Actions'; +import Actions, { ApiResponse } from '../../core/Actions'; import { InnertubeError } from '../../utils/Utils'; import MusicShelf from '../classes/MusicShelf'; @@ -16,11 +16,11 @@ class Artist { header; sections; - constructor(response: AxioslikeResponse | ParsedResponse, actions: Actions) { - this.#page = Parser.parseResponse((response as AxioslikeResponse).data); + constructor(response: ApiResponse | ParsedResponse, actions: Actions) { + this.#page = Parser.parseResponse((response as ApiResponse).data); this.#actions = actions; - this.header = this.page.header.item().as(MusicImmersiveHeader, MusicVisualHeader, MusicHeader); + this.header = this.page.header?.item().as(MusicImmersiveHeader, MusicVisualHeader, MusicHeader); const music_shelf = this.#page.contents_memo.get('MusicShelf') as MusicShelf[] || []; const music_carousel_shelf = this.#page.contents_memo.get('MusicCarouselShelf') as MusicCarouselShelf[] || []; @@ -42,7 +42,7 @@ class Artist { if (!shelf.endpoint) throw new InnertubeError('Target shelf (Songs) did not have an endpoint.'); - const page = await shelf.endpoint.call(this.#actions, 'YTMUSIC', true) as ParsedResponse; + const page = await shelf.endpoint.call(this.#actions, { client: 'YTMUSIC', parse: true }); const contents = page.contents_memo.get('MusicPlaylistShelf')?.[0]?.as(MusicPlaylistShelf) || null; return contents; diff --git a/src/parser/ytmusic/Explore.ts b/src/parser/ytmusic/Explore.ts index e33c4169..c5d15c7f 100644 --- a/src/parser/ytmusic/Explore.ts +++ b/src/parser/ytmusic/Explore.ts @@ -1,7 +1,7 @@ import Parser, { ParsedResponse } from '..'; import { InnertubeError } from '../../utils/Utils'; -import { AxioslikeResponse } from '../../core/Actions'; +import { ApiResponse } from '../../core/Actions'; import Grid from '../classes/Grid'; import SectionList from '../classes/SectionList'; @@ -15,7 +15,7 @@ class Explore { top_buttons; sections; - constructor(response: AxioslikeResponse) { + constructor(response: ApiResponse) { this.#page = Parser.parseResponse(response.data); const tab = this.#page.contents.item().as(SingleColumnBrowseResults).tabs.get({ selected: true }); @@ -28,7 +28,7 @@ class Explore { if (!section_list) throw new InnertubeError('Target tab did not have any content.'); - this.top_buttons = section_list.contents.array().firstOfType(Grid)?.items.array().as(MusicNavigationButton) || ([] as MusicNavigationButton[]); + this.top_buttons = section_list.contents.array().firstOfType(Grid)?.items.as(MusicNavigationButton) || ([] as MusicNavigationButton[]); this.sections = section_list.contents.array().getAll({ type: 'MusicCarouselShelf' }) as MusicCarouselShelf[]; } diff --git a/src/parser/ytmusic/HomeFeed.ts b/src/parser/ytmusic/HomeFeed.ts index ad64ed88..bdeb43f4 100644 --- a/src/parser/ytmusic/HomeFeed.ts +++ b/src/parser/ytmusic/HomeFeed.ts @@ -1,5 +1,5 @@ import Parser, { ParsedResponse, SectionListContinuation } from '../index'; -import Actions, { AxioslikeResponse } from '../../core/Actions'; +import Actions, { ApiResponse } from '../../core/Actions'; import { InnertubeError } from '../../utils/Utils'; import SectionList from '../classes/SectionList'; @@ -13,9 +13,9 @@ class HomeFeed { sections; - constructor(response: AxioslikeResponse | ParsedResponse, actions: Actions) { + constructor(response: ApiResponse | ParsedResponse, actions: Actions) { this.#actions = actions; - this.#page = Parser.parseResponse((response as AxioslikeResponse).data); + this.#page = Parser.parseResponse((response as ApiResponse).data); const tab = this.#page.contents.item().as(SingleColumnBrowseResults).tabs.get({ selected: true }); @@ -43,7 +43,11 @@ class HomeFeed { if (!this.#continuation) throw new InnertubeError('Continuation not found.'); - const response = await this.#actions.browse(this.#continuation, { is_ctoken: true, client: 'YTMUSIC' }); + const response = await this.#actions.execute('/browse', { + client: 'YTMUSIC', + continuation: this.#continuation + }); + return new HomeFeed(response, this.#actions); } diff --git a/src/parser/ytmusic/Library.ts b/src/parser/ytmusic/Library.ts index 85f19a1b..7035a9d7 100644 --- a/src/parser/ytmusic/Library.ts +++ b/src/parser/ytmusic/Library.ts @@ -1,323 +1,180 @@ -import Parser, { GridContinuation, MusicShelfContinuation, ParsedResponse, PlaylistPanelContinuation, SectionListContinuation } from '..'; -import Actions from '../../core/Actions'; -import { InnertubeError } from '../../utils/Utils'; +import Parser, { ParsedResponse } from '..'; +import Actions, { ApiResponse } from '../../core/Actions'; -import DropdownItem from '../classes/DropdownItem'; +import Grid from '../classes/Grid'; +import MusicShelf from '../classes/MusicShelf'; +import MusicSideAlignedItem from '../classes/MusicSideAlignedItem'; import NavigationEndpoint from '../classes/NavigationEndpoint'; -import PlaylistPanel from '../classes/PlaylistPanel'; import SectionList from '../classes/SectionList'; -type ContentType = 'history' | 'playlists' | 'albums' | 'songs' | 'artists' | 'subscriptions'; +import ChipCloud from '../classes/ChipCloud'; +import ChipCloudChip from '../classes/ChipCloudChip'; +import MusicMultiSelectMenuItem from '../classes/menus/MusicMultiSelectMenuItem'; +import MusicSortFilterButton from '../classes/MusicSortFilterButton'; +import MusicMenuItemDivider from '../classes/menus/MusicMenuItemDivider'; -type Continuation = { - type: 'browse' | 'next'; - token: string, - payload?: {} -}; - -type ItemFilter = ((item: any) => boolean) | null; -type SortBy = 'recently_added' | 'a_z' | 'z_a'; - -const BROWSE_IDS: { [key: string]: string } = { - 'history': 'FEmusic_history', - 'playlists': 'FEmusic_liked_playlists', - 'albums': 'FEmusic_liked_albums', - 'songs': 'FEmusic_liked_videos', - 'artists': 'FEmusic_library_corpus_track_artists', - 'subscriptions': 'FEmusic_library_corpus_artists' -}; - -const SORT_BY_TEXTS: { [key: string]: string } = { - 'recently_added': 'Recently added', - 'a_z': 'A to Z', - 'z_a': 'Z to A' -}; - -const SORT_BY_TEXTS_R: { [key: string]: string } = {}; -for (const [ key, value ] of Object.entries(SORT_BY_TEXTS)) { - SORT_BY_TEXTS_R[value] = key; -} +import { InnertubeError } from '../../utils/Utils'; class Library { - #actions; - - constructor(actions: Actions) { - this.#actions = actions; - } - - #getBrowseId(type: ContentType) { - return BROWSE_IDS[type]; - } - - async #fetchPage(browse_id: string, fetchArgs = {}) { - const response = await this.#actions.browse(browse_id, { ...fetchArgs, client: 'YTMUSIC' }); - return Parser.parseResponse(response.data); - } - - /** - * Fetches the list of library items from the endpoint given by `browse_id` - * @param browse_id - id of browse endpoint from which contents are fetched - * @param filter - The filter to apply to fetched items (`null` for no filtering) - * @param fetchArgs - Args to be included in the fetch payload - */ - async #fetchAndParseTabContents(browse_id: string, filter: ItemFilter = null, fetchArgs = {}) { - - const getItemsFromDataNode = (node: any) => { - switch (node?.type) { - case 'Grid': - return node.contents?.array(); - case 'MusicShelf': - return node.contents; - default: - return []; - } - }; - - const page = await this.#fetchPage(browse_id, fetchArgs); - const sections = page.contents_memo.get('SectionList')?.[0].as(SectionList).contents.array() as Array || []; - const contents_section = sections.find((section) => section.header?.type === 'ItemSectionTabbedHeader'); - const data_node = contents_section?.contents?.[0]; - const continuation = data_node?.continuation ? { - type: 'browse', - token: data_node?.continuation - } as Continuation : null; - return new LibraryItemList(getItemsFromDataNode(data_node) || [], filter, continuation, page, this.#actions); - } - - /** - * Retrieves the library's playlists - */ - async getPlaylists(args?: { sort_by?: SortBy }) { - const data = await this.#fetchAndParseTabContents(this.#getBrowseId('playlists'), (item) => item.item_type === 'playlist'); - const sort_by = args?.sort_by || null; - return sort_by ? this.#applySortBy(data, sort_by) : data; - } - - /** - * Retrieves the library's albums - */ - async getAlbums(args?: { sort_by?: SortBy }) { - const data = await this.#fetchAndParseTabContents(this.#getBrowseId('albums'), (item) => item.item_type === 'album'); - const sort_by = args?.sort_by || null; - return sort_by ? this.#applySortBy(data, sort_by) : data; - } - - /** - * Retrieves the library's artists - */ - async getArtists(args?: { sort_by?: SortBy }) { - const data = await this.#fetchAndParseTabContents(this.#getBrowseId('artists'), (item) => item.item_type === 'library_artist'); - const sort_by = args?.sort_by || null; - return sort_by ? this.#applySortBy(data, sort_by) : data; - } - - /** - * Retrieves the library's songs - */ - async getSongs(args?: { sort_by?: SortBy | 'random' }) { - const data = await this.#fetchAndParseTabContents(this.#getBrowseId('songs'), (item) => (item.item_type === 'song' || item.item_type === 'video')); - - const sort_by = args?.sort_by || null; - const shuffle = (sort_by === 'random'); - - const shuffle_endpoint = shuffle ? - data.all_items.find((item) => - item.item_type === 'endpoint' && item.title.toString() === 'Shuffle all' - )?.endpoint as NavigationEndpoint : null; - - if (shuffle) { - if (!shuffle_endpoint) { - if (data.items.length <= 1) { - return data; - } - throw new InnertubeError('Unable to obtain endpoint for sort_by value \'random\''); - } - return this.#fetchAndParseShuffledSongs(shuffle_endpoint); - } - - return sort_by ? this.#applySortBy(data, sort_by) : data; - } - - /** - * Fetches and returns a list of shuffled songs - * @param endpoint - The endpoint of the playlist containing the shuffled songs - */ - async #fetchAndParseShuffledSongs(endpoint: NavigationEndpoint) { - const payload = { - playlist_id: endpoint.payload.playlistId, - params: endpoint.payload.params - }; - const response = await this.#actions.next({ ...payload, client: 'YTMUSIC' }); - const page = Parser.parseResponse(response.data); - const playlist_panel = page.contents_memo.get('PlaylistPanel')?.[0].as(PlaylistPanel); - const items = playlist_panel?.contents || []; - const continuation = playlist_panel?.continuation ? { - type: 'next', - token: playlist_panel?.continuation, - payload - } as Continuation : null; - const filter = (item: any) => item.type === 'PlaylistPanelVideo'; - return new LibraryItemList(items, filter, continuation, page, this.#actions, { sort_by: 'random' }); - } - - /** - * Retrieves the library's subscriptions - */ - async getSubscriptions(args?: { sort_by?: SortBy }) { - const data = await this.#fetchAndParseTabContents(this.#getBrowseId('subscriptions')); - const sort_by = args?.sort_by || null; - return sort_by ? this.#applySortBy(data, sort_by) : data; - } - - /** - * Applies `sort_by` to `data` and returns the result. Original `data` is not modified. - */ - async #applySortBy(data: LibraryItemList, sort_by: SortBy) { - const page = data.page; - const dropdownItem = page?.contents_memo.get('DropdownItem')?.find( - (item) => item.as(DropdownItem).label === SORT_BY_TEXTS[sort_by])?.as(DropdownItem); - - if (!dropdownItem?.endpoint?.browse) { - if (data.items.length <= 1) { - return data; - } - throw new InnertubeError(`Unable to obtain browse endpoint for sort_by value '${sort_by}'`); - } - - if (dropdownItem?.selected) { - return data; - } - - const fetchArgs = { params: dropdownItem.endpoint.browse.params }; - return this.#fetchAndParseTabContents(dropdownItem.endpoint.browse.id, data.filter, fetchArgs); - } - - /** - * Retrieves recent activity - */ - async getRecentActivity(args: {all: boolean}) { - const all = !!args?.all; - if (all) { - const page = await this.#fetchPage(this.#getBrowseId('history')); - const section_list = page.contents_memo.get('SectionList')?.[0].as(SectionList); - const sections = section_list?.contents?.array() || []; - const continuation = section_list?.continuation ? { - type: 'browse', - token: section_list?.continuation - } as Continuation : null; - return new LibrarySectionList(sections, continuation, page, this.#actions); - } - - const page = await this.#fetchPage(this.#getBrowseId('songs')); - const sections = page.contents_memo.get('SectionList')?.[0].as(SectionList).contents.array() as Array || []; - const contents_section = sections.find( - (section) => section.header?.type === 'MusicCarouselShelfBasicHeader' && section.header?.title.toString() === 'Recent activity'); - const items = contents_section?.contents || []; - return new LibraryItemList(items, null, null, page, this.#actions, { sort_by: null }); - } -} - -abstract class LibraryResultsBase { - #continuation; #page; #actions; - has_continuation: boolean; + #continuation; - constructor(continuation: Continuation | null, page: ParsedResponse, actions: Actions) { - this.#continuation = continuation; - this.#page = page; + header; + contents; + + constructor(response: ApiResponse, actions: Actions) { + this.#page = Parser.parseResponse(response.data); this.#actions = actions; - this.has_continuation = !!continuation; + + const section_list = this.#page.contents_memo.getType(SectionList)?.[0]; + + this.header = section_list?.header?.item().as(MusicSideAlignedItem); + this.contents = section_list?.contents?.array().as(Grid, MusicShelf); + + this.#continuation = this.contents?.find((list: Grid | MusicShelf) => list.continuation)?.continuation; } - async getContinuation() { - if (!this.#continuation) { - throw new InnertubeError('Continuation not found.'); + /** + * Applies given sort filter to the library items. + */ + async applySortFilter(sort_by: string | MusicMultiSelectMenuItem) { + let target_item: MusicMultiSelectMenuItem | undefined; + + if (typeof sort_by === 'string') { + const button = this.#page.contents_memo.getType(MusicSortFilterButton)?.[0]; + + const options = button.menu?.options + .filter( + (item: MusicMultiSelectMenuItem | MusicMenuItemDivider) => item instanceof MusicMultiSelectMenuItem + ) as MusicMultiSelectMenuItem[]; + + target_item = options?.find((item) => item.title === sort_by); + + if (!target_item) + throw new InnertubeError(`Sort filter "${sort_by}" not found`, { available_filters: options.map((item) => item.title) }); + } else if (sort_by instanceof MusicMultiSelectMenuItem) { + target_item = sort_by; } - let responsePromise; - const payload = this.#continuation.payload || {}; - switch (this.#continuation.type) { - case 'next': - responsePromise = this.#actions.next({ ...payload, ctoken: this.#continuation.token, client: 'YTMUSIC' }); - break; - default: - responsePromise = this.#actions.browse(this.#continuation.token, { ...payload, is_ctoken: true, client: 'YTMUSIC' }); - } - const response = await responsePromise; - const page = Parser.parseResponse(response.data); + if (!target_item) + throw new InnertubeError('Invalid sort filter'); - if (!page.continuation_contents) { - throw new InnertubeError('No continuation data found.'); - } + if (target_item.selected) + return this; - return this.parseContinuationContents(page, this.#continuation); + const cmd = target_item.endpoint?.payload?.commands?.find((cmd: any) => cmd.browseSectionListReloadEndpoint)?.browseSectionListReloadEndpoint; + + if (!cmd) + throw new InnertubeError('Failed to find sort filter command'); + + const response = await this.#actions.execute('/browse', { + client: 'YTMUSIC', + continuation: cmd.continuation.reloadContinuationData.continuation + }); + + return new Library(response, this.#actions); } - get page() { + /** + * Applies given filter to the library. + */ + async applyFilter(filter: string | ChipCloudChip): Promise { + let target_chip: ChipCloudChip | undefined; + + const chip_cloud = this.#page.contents_memo.getType(ChipCloud)?.[0]; + + if (typeof filter === 'string') { + target_chip = chip_cloud.chips.get({ text: filter }); + + if (!target_chip) + throw new InnertubeError(`Filter "${filter}" not found`, { available_filters: this.filters }); + } else if (filter instanceof ChipCloudChip) { + target_chip = filter; + } + + if (!target_chip) + throw new InnertubeError('Invalid filter', filter); + + const target_cmd = new NavigationEndpoint(target_chip.endpoint?.payload?.commands?.[0]); + const response = await target_cmd.call(this.#actions, { client: 'YTMUSIC' }); + + return new Library(response, this.#actions); + } + + /** + * Retrieves continuation of the library items. + */ + async getContinuation(): Promise { + if (!this.#continuation) + throw new InnertubeError('No continuation available'); + + const page = await this.#actions.execute('/browse', { + client: 'YTMUSIC', + continuation: this.#continuation + }); + + return new LibraryContinuation(page, this.#actions); + } + + get has_continuation(): boolean { + return !!this.#continuation; + } + + get sort_filters(): string[] { + const button = this.#page.contents_memo.getType(MusicSortFilterButton)?.[0]; + const options = button.menu?.options.filter((item: MusicMultiSelectMenuItem | MusicMenuItemDivider) => item instanceof MusicMultiSelectMenuItem) as MusicMultiSelectMenuItem[]; + return options.map((item) => item.title); + } + + get filters(): string[] { + return this.#page.contents_memo.getType(ChipCloud)?.[0].chips.map((chip: ChipCloudChip) => chip.text); + } + + get page(): ParsedResponse { return this.#page; } - - abstract parseContinuationContents(page: ParsedResponse, from_continuation: Continuation): Promise; } -class LibraryItemList extends LibraryResultsBase { - #filter; +class LibraryContinuation { + #page; #actions; - #all_items; // Unfiltered items - items; // Items after applying filter (if any) - sort_by: SortBy | 'random' | null; + #continuation; - constructor(items: Array, filter: ItemFilter, continuation: Continuation | null, page: ParsedResponse, actions: Actions, overrides?: { sort_by: SortBy | 'random' | null }) { - super(continuation, page, actions); - this.#filter = filter; + contents; + + constructor(response: ApiResponse, actions: Actions) { + this.#page = Parser.parseResponse(response.data); this.#actions = actions; - this.#all_items = items; - this.items = filter ? items.filter(filter) : items; - this.sort_by = (overrides?.sort_by !== undefined) ? overrides.sort_by : this.#getSortBy(); + + this.contents = this.#page.continuation_contents?.hasKey('contents') + ? this.#page.continuation_contents?.key('contents').array() : + this.#page.continuation_contents?.key('items').array(); + + this.#continuation = this.#page.continuation_contents?.key('continuation').isNull() + ? null : this.#page.continuation_contents?.key('continuation').string(); } - async parseContinuationContents(page: ParsedResponse, from_continuation: Continuation) { - const data = page.continuation_contents?.as(MusicShelfContinuation, GridContinuation, PlaylistPanelContinuation); - const continuation = data?.continuation ? { ...from_continuation, token: data?.continuation } : null; - return new LibraryItemList(data?.contents || [], this.#filter, continuation, page, this.#actions, { sort_by: this.sort_by }); + async getContinuation(): Promise { + if (!this.#continuation) + throw new InnertubeError('No continuation available'); + + const page = await this.#actions.execute('/browse', { + client: 'YTMUSIC', + continuation: this.#continuation + }); + + return new LibraryContinuation(page, this.#actions); } - #getSortBy() { - const selected = this.page?.contents_memo.get('DropdownItem')?.filter((item) => item.as(DropdownItem).selected) as DropdownItem[] || []; - for (const s of selected) { - const v = SORT_BY_TEXTS_R[s.label]; - if (v) { - return v as SortBy; - } - } - return null; + get has_continuation(): boolean { + return !!this.#continuation; } - get all_items() { - return this.#all_items; - } - - get filter() { - return this.#filter; - } -} - -class LibrarySectionList extends LibraryResultsBase { - #actions; - sections; - - constructor(sections: Array, continuation: Continuation | null, page: ParsedResponse, actions: Actions) { - super(continuation, page, actions); - this.#actions = actions; - this.sections = sections; - } - - async parseContinuationContents(page: ParsedResponse, from_continuation: Continuation) { - const data = page.continuation_contents?.as(SectionListContinuation); - const continuation = data?.continuation ? { ...from_continuation, token: data?.continuation } : null; - return new LibrarySectionList(data?.contents || [], continuation, page, this.#actions); + get page(): ParsedResponse { + return this.#page; } } +export { LibraryContinuation }; export default Library; \ No newline at end of file diff --git a/src/parser/ytmusic/Playlist.ts b/src/parser/ytmusic/Playlist.ts index 4588c42f..cc1e178f 100644 --- a/src/parser/ytmusic/Playlist.ts +++ b/src/parser/ytmusic/Playlist.ts @@ -1,5 +1,5 @@ -import Parser, { MusicPlaylistShelfContinuation, MusicShelfContinuation, ParsedResponse, SectionListContinuation } from '../index'; -import Actions, { AxioslikeResponse } from '../../core/Actions'; +import Parser, { MusicPlaylistShelfContinuation, ParsedResponse, SectionListContinuation } from '../index'; +import Actions, { ApiResponse } from '../../core/Actions'; import MusicCarouselShelf from '../classes/MusicCarouselShelf'; import MusicPlaylistShelf from '../classes/MusicPlaylistShelf'; @@ -15,19 +15,18 @@ class Playlist { #page; #actions; #continuation; - #suggestions_continuation; #last_fetched_suggestions: any; + #suggestions_continuation: any; header; items; - constructor(response: AxioslikeResponse, actions: Actions) { + constructor(response: ApiResponse, actions: Actions) { this.#actions = actions; this.#page = Parser.parseResponse(response.data); - this.#suggestions_continuation = this.#page.contents_memo.getType(MusicShelf)?.find( - (shelf) => shelf.title.toString() === 'Suggestions')?.continuation || null; this.#last_fetched_suggestions = null; + this.#suggestions_continuation = null; if (this.#page.continuation_contents) { const data = this.#page.continuation_contents?.as(MusicPlaylistShelfContinuation); @@ -44,14 +43,6 @@ class Playlist { } } - get page(): ParsedResponse { - return this.#page; - } - - get has_continuation() { - return !!this.#continuation; - } - /** * Retrieves playlist items continuation. */ @@ -59,7 +50,11 @@ class Playlist { if (!this.#continuation) throw new InnertubeError('Continuation not found.'); - const response = await this.#actions.browse(this.#continuation, { is_ctoken: true, client: 'YTMUSIC' }); + const response = await this.#actions.execute('/browse', { + client: 'YTMUSIC', + continuation: this.#continuation + }); + return new Playlist(response, this.#actions); } @@ -70,17 +65,25 @@ class Playlist { let section_continuation = this.#page.contents_memo.get('SectionList')?.[0].as(SectionList).continuation; while (section_continuation) { - const response = await this.#actions.browse(section_continuation, { is_ctoken: true, client: 'YTMUSIC' }); - const data = Parser.parseResponse(response.data); + const data = await this.#actions.execute('/browse', { + client: 'YTMUSIC', + continuation: section_continuation, + parse: true + }); + const section_list = data.continuation_contents?.as(SectionListContinuation); - const sections = section_list?.contents?.as(MusicCarouselShelf); - const related = sections?.filter((section) => section.header?.title.toString() === 'Related playlists')[0]; - if (related) { + const sections = section_list?.contents?.as(MusicCarouselShelf, MusicShelf); + + const related = sections?.filter( + (section) => + section.is(MusicCarouselShelf) ? section.header?.title.toString() === 'Related playlists' : + section.title.toString() === 'Related playlists' + )[0]; + + if (related) return related.contents || []; - } section_continuation = section_list?.continuation; - } return []; @@ -88,7 +91,7 @@ class Playlist { async getSuggestions(refresh = true) { const require_fetch = refresh || !this.#last_fetched_suggestions; - const fetch_promise = require_fetch ? this.#fetchSuggestions(this.#suggestions_continuation) : Promise.resolve(null); + const fetch_promise = require_fetch ? this.#fetchSuggestions() : Promise.resolve(null); const fetch_result = await fetch_promise; if (fetch_result) { @@ -99,14 +102,26 @@ class Playlist { return fetch_result?.items || this.#last_fetched_suggestions; } - async #fetchSuggestions(continuation: string | null) { + async #fetchSuggestions() { + const continuation = this.#suggestions_continuation || this.#page.contents_memo.get('SectionList')?.[0].as(SectionList).continuation; + if (continuation) { - const response = await this.#actions.browse(continuation, { is_ctoken: true, client: 'YTMUSIC' }); - const page = Parser.parseResponse(response.data); - const data = page.continuation_contents?.as(MusicShelfContinuation); + const page = await this.#actions.execute('/browse', { + client: 'YTMUSIC', + continuation: continuation, + parse: true + }); + + const section_list = page.continuation_contents?.as(SectionListContinuation); + const sections = section_list?.contents?.as(MusicCarouselShelf, MusicShelf); + + const suggestions = sections?.filter( + (section) => section.is(MusicShelf) && section.title.toString() === 'Suggestions' + )[0] as MusicShelf | undefined; + return { - items: data?.contents || [], - continuation: data?.continuation || null + items: suggestions?.contents || [], + continuation: suggestions?.continuation || null }; } @@ -115,6 +130,14 @@ class Playlist { continuation: null }; } + + get page(): ParsedResponse { + return this.#page; + } + + get has_continuation() { + return !!this.#continuation; + } } export default Playlist; \ No newline at end of file diff --git a/src/parser/ytmusic/Recap.ts b/src/parser/ytmusic/Recap.ts index 721e6f88..e8e9c0fb 100644 --- a/src/parser/ytmusic/Recap.ts +++ b/src/parser/ytmusic/Recap.ts @@ -1,5 +1,5 @@ import Parser, { ParsedResponse } from '../index'; -import Actions, { AxioslikeResponse } from '../../core/Actions'; +import Actions, { ApiResponse } from '../../core/Actions'; import Playlist from './Playlist'; import MusicHeader from '../classes/MusicHeader'; @@ -22,15 +22,15 @@ class Recap { header; sections; - constructor(response: AxioslikeResponse, actions: Actions) { + constructor(response: ApiResponse, actions: Actions) { this.#page = Parser.parseResponse(response.data); this.#actions = actions; - const header = this.#page.header.item(); + const header = this.#page.header?.item(); - this.header = header.is(MusicElementHeader) ? - this.#page.header.item().as(MusicElementHeader).element?.model?.item().as(HighlightsCarousel) : - this.#page.header.item().as(MusicHeader); + this.header = header?.is(MusicElementHeader) ? + this.#page.header?.item().as(MusicElementHeader).element?.model?.item().as(HighlightsCarousel) : + this.#page.header?.item().as(MusicHeader); const tab = this.#page.contents.item().as(SingleColumnBrowseResults).tabs.firstOfType(Tab); @@ -51,7 +51,7 @@ class Recap { throw new InnertubeError('Recap playlist not available, check back later.'); const endpoint = this.header.panels[0].text_on_tap_endpoint; - const response = await endpoint.callTest(this.#actions, { client: 'YTMUSIC' }); + const response = await endpoint.call(this.#actions, { client: 'YTMUSIC' }); return new Playlist(response, this.#actions); } diff --git a/src/parser/ytmusic/Search.ts b/src/parser/ytmusic/Search.ts index 5591f6de..b50e72ef 100644 --- a/src/parser/ytmusic/Search.ts +++ b/src/parser/ytmusic/Search.ts @@ -1,5 +1,5 @@ import Parser, { ParsedResponse } from '../index'; -import Actions, { AxioslikeResponse } from '../../core/Actions'; +import Actions, { ApiResponse } from '../../core/Actions'; import { InnertubeError } from '../../utils/Utils'; @@ -30,12 +30,12 @@ class Search { results; sections; - constructor(response: AxioslikeResponse | ParsedResponse, actions: Actions, args: { is_continuation?: boolean, is_filtered?: boolean } = {}) { + constructor(response: ApiResponse | ParsedResponse, actions: Actions, args: { is_continuation?: boolean, is_filtered?: boolean } = {}) { this.#actions = actions; this.#page = args.is_continuation ? response as ParsedResponse : - Parser.parseResponse((response as AxioslikeResponse).data); + Parser.parseResponse((response as ApiResponse).data); const tab = this.#page.contents.item().as(TabbedSearchResults).tabs.get({ selected: true }); @@ -71,7 +71,7 @@ class Search { if (!shelf || !shelf.endpoint) throw new InnertubeError('Cannot retrieve more items for this shelf because it does not have an endpoint.'); - const response = await shelf.endpoint.call(this.#actions, 'YTMUSIC', true); + const response = await shelf.endpoint.call(this.#actions, { parse: true, client: 'YTMUSIC' }); if (!response) throw new InnertubeError('Endpoint did not return any data'); @@ -86,7 +86,11 @@ class Search { if (!this.#continuation) throw new InnertubeError('Continuation not found.'); - const response = await this.#actions.search({ ctoken: this.#continuation, client: 'YTMUSIC' }); + const response = await this.#actions.execute('/search', { + continuation: this.#continuation, + client: 'YTMUSIC' + }); + const data = response.data.continuationContents.musicShelfContinuation; this.results = Parser.parse(data.contents).array().as(MusicResponsiveListItem); @@ -106,7 +110,7 @@ class Search { if (filter?.is_selected) return this; - const response = await filter?.endpoint?.call(this.#actions, 'YTMUSIC', true); + const response = await filter?.endpoint?.call(this.#actions, { parse: true, client: 'YTMUSIC' }); if (!response) throw new InnertubeError('Endpoint did not return any data'); diff --git a/src/parser/ytmusic/TrackInfo.ts b/src/parser/ytmusic/TrackInfo.ts index 294a775d..47cff7d1 100644 --- a/src/parser/ytmusic/TrackInfo.ts +++ b/src/parser/ytmusic/TrackInfo.ts @@ -1,5 +1,5 @@ import Parser, { ParsedResponse } from '..'; -import Actions, { AxioslikeResponse } from '../../core/Actions'; +import Actions, { ApiResponse } from '../../core/Actions'; import Constants from '../../utils/Constants'; import { InnertubeError } from '../../utils/Utils'; @@ -36,7 +36,7 @@ class TrackInfo { current_video_endpoint; player_overlays; - constructor(data: [AxioslikeResponse, AxioslikeResponse?], actions: Actions, cpn: string) { + constructor(data: [ApiResponse, ApiResponse?], actions: Actions, cpn: string) { this.#actions = actions; const info = Parser.parseResponse(data[0].data); @@ -96,7 +96,7 @@ class TrackInfo { if (target_tab.content) return target_tab.content; - const page = await target_tab.endpoint.callTest(this.#actions, { client: 'YTMUSIC', parse: true }); + const page = await target_tab.endpoint.call(this.#actions, { client: 'YTMUSIC', parse: true }); if (page.contents.item().key('type').string() === 'Message') return page.contents.item().as(Message); @@ -121,7 +121,7 @@ class TrackInfo { if (!automix_preview_video) throw new InnertubeError('Automix item not found'); - const page = await automix_preview_video.playlist_video?.endpoint.callTest(this.#actions, { + const page = await automix_preview_video.playlist_video?.endpoint.call(this.#actions, { videoId: this.basic_info.id, client: 'YTMUSIC', parse: true diff --git a/src/proto/index.ts b/src/proto/index.ts index ef98cc73..9262e6b8 100644 --- a/src/proto/index.ts +++ b/src/proto/index.ts @@ -1,7 +1,8 @@ import { CLIENTS } from '../utils/Constants'; import { u8ToBase64 } from '../utils/Utils'; import { VideoMetadata } from '../core/Studio'; -import { ChannelAnalytics, CreateCommentParams, CreateCommentReplyParams, GetCommentsSectionParams, InnertubePayload, LiveMessageParams, MusicSearchFilter, NotificationPreferences, PeformCommentActionParams, SearchFilter, SoundInfoParams } from './youtube'; + +import { ChannelAnalytics, CreateCommentParams, GetCommentsSectionParams, InnertubePayload, LiveMessageParams, MusicSearchFilter, NotificationPreferences, PeformCommentActionParams, SearchFilter } from './youtube'; class Proto { static encodeChannelAnalyticsParams(channel_id: string) { @@ -139,28 +140,6 @@ class Proto { return encodeURIComponent(u8ToBase64(buf)); } - static encodeCommentRepliesParams(video_id: string, comment_id: string) { - const buf = GetCommentsSectionParams.toBinary({ - ctx: { - videoId: video_id - }, - unkParam: 6, - params: { - repliesOpts: { - videoId: video_id, commentId: comment_id, - unkopts: { - unkParam: 0 - }, - unkParam1: 1, unkParam2: 10, - channelId: ' ' // XXX: Seems like this can be omitted - }, - target: `comment-replies-item-${comment_id}` - } - }); - - return encodeURIComponent(u8ToBase64(buf)); - } - static encodeCommentParams(video_id: string) { const buf = CreateCommentParams.toBinary({ videoId: video_id, @@ -172,18 +151,6 @@ class Proto { return encodeURIComponent(u8ToBase64(buf)); } - static encodeCommentReplyParams(comment_id: string, video_id: string) { - const buf = CreateCommentReplyParams.toBinary({ - videoId: video_id, - commentId: comment_id, - params: { - unkNum: 0 - }, - unkNum: 7 - }); - return encodeURIComponent(u8ToBase64(buf)); - } - static encodeCommentActionParams(type: number, args: { comment_id?: string, video_id?: string, @@ -312,23 +279,6 @@ class Proto { return buf; } - - static encodeSoundInfoParams(id: string) { - const data: SoundInfoParams = { - sound: { - params: { - ids: { - id1: id, - id2: id, - id3: id - } - } - } - }; - - const buf = SoundInfoParams.toBinary(data); - return encodeURIComponent(u8ToBase64(buf)); - } } export default Proto; \ No newline at end of file diff --git a/src/proto/youtube.proto b/src/proto/youtube.proto index 21e2776b..9d7e151d 100644 --- a/src/proto/youtube.proto +++ b/src/proto/youtube.proto @@ -186,18 +186,6 @@ message CreateCommentParams { required int32 number = 10; } -message CreateCommentReplyParams { - required string video_id = 2; - required string comment_id = 4; - - message UnknownParams { - required int32 unk_num = 1; - } - required UnknownParams params = 5; - - optional int32 unk_num = 10; -} - message PeformCommentActionParams { required int32 type = 1; required string comment_id = 3; diff --git a/src/utils/Utils.ts b/src/utils/Utils.ts index 685cede1..9a097d41 100644 --- a/src/utils/Utils.ts +++ b/src/utils/Utils.ts @@ -1,4 +1,5 @@ import package_json from '../../package.json'; +import { Memo } from '../parser/helpers'; import { FetchFunction } from './HTTPClient'; import userAgents from './user-agents.json'; @@ -151,9 +152,18 @@ export function timeToSeconds(time: string) { } } -/** - * Throws an error if given parameters are undefined. - */ +export function concatMemos(...iterables: Memo[]) { + const memo = new Memo(); + + for (const iterable of iterables) { + for (const item of iterable) { + memo.set(...item); + } + } + + return memo; +} + export function throwIfMissing(params: object) { for (const [ key, value ] of Object.entries(params)) { if (!value)