From 37d800259b4b04311056f7bac71f4edcbd905f0e Mon Sep 17 00:00:00 2001 From: ArabCoders Date: Tue, 31 Dec 2024 21:48:50 +0300 Subject: [PATCH 1/6] Added new getLibraryContent to retrieve entire library section content. --- config/services.php | 25 +++++-- src/Backends/Common/ClientInterface.php | 9 +++ src/Backends/Emby/EmbyClient.php | 52 +++++++++++++++ src/Backends/Jellyfin/Action/Import.php | 14 +++- src/Backends/Jellyfin/JellyfinClient.php | 52 +++++++++++++++ src/Backends/Plex/Action/Import.php | 9 ++- src/Backends/Plex/PlexClient.php | 52 +++++++++++++++ src/Libs/Mappers/Import/MemoryMapper.php | 3 +- src/Libs/Mappers/Import/ReadOnlyMapper.php | 76 ++++++++++++++++++++++ src/Libs/Options.php | 1 + 10 files changed, 283 insertions(+), 10 deletions(-) create mode 100644 src/Libs/Mappers/Import/ReadOnlyMapper.php diff --git a/config/services.php b/config/services.php index dd30bd0e..08dd50f5 100644 --- a/config/services.php +++ b/config/services.php @@ -16,6 +16,7 @@ use App\Libs\LogSuppressor; use App\Libs\Mappers\Import\DirectMapper; use App\Libs\Mappers\Import\MemoryMapper; +use App\Libs\Mappers\Import\ReadOnlyMapper; use App\Libs\Mappers\ImportInterface as iImport; use App\Libs\QueueRequests; use App\Libs\Uri; @@ -23,7 +24,7 @@ use Psr\EventDispatcher\EventDispatcherInterface; use Psr\Http\Message\UriInterface; use Psr\Log\LoggerInterface as iLogger; -use Psr\SimpleCache\CacheInterface; +use Psr\SimpleCache\CacheInterface as iCache; use Symfony\Component\Cache\Adapter\ArrayAdapter; use Symfony\Component\Cache\Adapter\FilesystemAdapter; use Symfony\Component\Cache\Adapter\NullAdapter; @@ -116,7 +117,7 @@ } ], - CacheInterface::class => [ + iCache::class => [ 'class' => function () { if (true === (bool)env('WS_CACHE_NULL', false)) { return new Psr16Cache(new NullAdapter()); @@ -238,26 +239,38 @@ ], MemoryMapper::class => [ - 'class' => function (iLogger $logger, iDB $db, CacheInterface $cache): iImport { + 'class' => function (iLogger $logger, iDB $db, iCache $cache): iImport { return new MemoryMapper(logger: $logger, db: $db, cache: $cache) ->setOptions(options: Config::get('mapper.import.opts', [])); }, 'args' => [ iLogger::class, iDB::class, - CacheInterface::class + iCache::class + ], + ], + + ReadOnlyMapper::class => [ + 'class' => function (iLogger $logger, iDB $db, iCache $cache): iImport { + return new ReadOnlyMapper(logger: $logger, db: $db, cache: $cache) + ->setOptions(options: Config::get('mapper.import.opts', [])); + }, + 'args' => [ + iLogger::class, + iDB::class, + iCache::class ], ], DirectMapper::class => [ - 'class' => function (iLogger $logger, iDB $db, CacheInterface $cache): iImport { + 'class' => function (iLogger $logger, iDB $db, iCache $cache): iImport { return new DirectMapper(logger: $logger, db: $db, cache: $cache) ->setOptions(options: Config::get('mapper.import.opts', [])); }, 'args' => [ iLogger::class, iDB::class, - CacheInterface::class + iCache::class ], ], diff --git a/src/Backends/Common/ClientInterface.php b/src/Backends/Common/ClientInterface.php index 1a445007..083ba105 100644 --- a/src/Backends/Common/ClientInterface.php +++ b/src/Backends/Common/ClientInterface.php @@ -173,6 +173,15 @@ public function searchId(string|int $id, array $opts = []): array; */ public function getMetadata(string|int $id, array $opts = []): array; + /** + * Get entire library content. + * + * @param string|int $libraryId library id. + * @param array $opts options. + * @return array|array empty array if no items found. + */ + public function getLibraryContent(string|int $libraryId, array $opts = []): array; + /** * Get Library content. * diff --git a/src/Backends/Emby/EmbyClient.php b/src/Backends/Emby/EmbyClient.php index f61fa72c..21a84f2b 100644 --- a/src/Backends/Emby/EmbyClient.php +++ b/src/Backends/Emby/EmbyClient.php @@ -35,6 +35,7 @@ use App\Libs\Entity\StateInterface as iState; use App\Libs\Exceptions\Backends\RuntimeException; use App\Libs\Exceptions\HttpException; +use App\Libs\Mappers\Import\ReadOnlyMapper; use App\Libs\Mappers\ImportInterface as iImport; use App\Libs\Options; use App\Libs\QueueRequests; @@ -44,6 +45,7 @@ use Psr\Http\Message\StreamInterface; use Psr\Http\Message\UriInterface; use Psr\Log\LoggerInterface as iLogger; +use Throwable; /** * Class EmbyClient @@ -404,6 +406,56 @@ public function getMetadata(string|int $id, array $opts = []): array return $response->response; } + /** + * @inheritdoc + */ + public function getLibraryContent(string|int $libraryId, array $opts = []): array + { + $mapper = Container::get(ReadOnlyMapper::class)->withOptions([]); + assert($mapper instanceof ReadOnlyMapper); + $mapper->asContainer(); + + $response = Container::get(Import::class)( + context: $this->context, + guid: $this->guid, + mapper: $mapper, + after: null, + opts: [ + Options::DISABLE_GUID => (bool)Config::get('episodes.disable.guid'), + Options::ONLY_LIBRARY_ID => $libraryId, + ...$opts, + ] + ); + + if ($response->hasError()) { + $this->logger->log($response->error->level(), $response->error->message, $response->error->context); + } + + if (false === $response->isSuccessful()) { + $this->throwError($response); + } + + if (null === ($queue = $response->response)) { + return []; + } + + foreach ($queue as $_key => $response) { + $requestData = $response->getInfo('user_data'); + + try { + $requestData['ok']($response); + } catch (Throwable $e) { + $requestData['error']($e); + } + + $queue[$_key] = null; + + gc_collect_cycles(); + } + + return $mapper->getObjects(); + } + /** * @inheritdoc */ diff --git a/src/Backends/Jellyfin/Action/Import.php b/src/Backends/Jellyfin/Action/Import.php index 6c197e9b..0e708d74 100644 --- a/src/Backends/Jellyfin/Action/Import.php +++ b/src/Backends/Jellyfin/Action/Import.php @@ -113,6 +113,7 @@ public function __invoke( ], ] ), + opts: $opts ), action: $this->action, ); @@ -124,10 +125,11 @@ public function __invoke( * @param Context $context Backend context. * @param Closure $handle The closure to handle a successful response. * @param Closure $error The closure to handle an error response. + * @param array $opts (Optional) Options. * * @return array The array of libraries retrieved from the backend. */ - protected function getLibraries(Context $context, Closure $handle, Closure $error): array + protected function getLibraries(Context $context, Closure $handle, Closure $error, array $opts = []): array { try { $url = $context->backendUrl->withPath(r('/Users/{user_id}/items/', ['user_id' => $context->backendUser])); @@ -273,19 +275,27 @@ protected function getLibraries(Context $context, Closure $handle, Closure $erro $ignoreIds = array_map(fn($v) => trim($v), explode(',', (string)$ignoreIds)); } + $limitLibraryId = ag($opts, Options::ONLY_LIBRARY_ID, null); + $requests = $total = []; $ignored = $unsupported = 0; // -- Get library items count. foreach ($listDirs as $section) { + $libraryId = (string)ag($section, 'Id'); + $logContext = [ 'library' => [ - 'id' => (string)ag($section, 'Id'), + 'id' => $libraryId, 'title' => ag($section, 'Name', '??'), 'type' => ag($section, 'CollectionType', 'unknown'), ], ]; + if (null !== $limitLibraryId && $libraryId !== (string)$limitLibraryId) { + continue; + } + if (true === in_array(ag($logContext, 'library.id'), $ignoreIds ?? [])) { continue; } diff --git a/src/Backends/Jellyfin/JellyfinClient.php b/src/Backends/Jellyfin/JellyfinClient.php index 538e6e42..4ca15f72 100644 --- a/src/Backends/Jellyfin/JellyfinClient.php +++ b/src/Backends/Jellyfin/JellyfinClient.php @@ -37,6 +37,7 @@ use App\Libs\Exceptions\Backends\RuntimeException; use App\Libs\Exceptions\Backends\UnexpectedVersionException; use App\Libs\Exceptions\HttpException; +use App\Libs\Mappers\Import\ReadOnlyMapper; use App\Libs\Mappers\ImportInterface as iImport; use App\Libs\Options; use App\Libs\QueueRequests; @@ -46,6 +47,7 @@ use Psr\Http\Message\StreamInterface; use Psr\Http\Message\UriInterface; use Psr\Log\LoggerInterface as iLogger; +use Throwable; /** * Class JellyfinClient @@ -445,6 +447,56 @@ public function getMetadata(string|int $id, array $opts = []): array return $response->response; } + /** + * @inheritdoc + */ + public function getLibraryContent(string|int $libraryId, array $opts = []): array + { + $mapper = Container::get(ReadOnlyMapper::class)->withOptions([]); + assert($mapper instanceof ReadOnlyMapper); + $mapper->asContainer(); + + $response = Container::get(Import::class)( + context: $this->context, + guid: $this->guid, + mapper: $mapper, + after: null, + opts: [ + Options::DISABLE_GUID => (bool)Config::get('episodes.disable.guid'), + Options::ONLY_LIBRARY_ID => $libraryId, + ...$opts, + ] + ); + + if ($response->hasError()) { + $this->logger->log($response->error->level(), $response->error->message, $response->error->context); + } + + if (false === $response->isSuccessful()) { + $this->throwError($response); + } + + if (null === ($queue = $response->response)) { + return []; + } + + foreach ($queue as $_key => $response) { + $requestData = $response->getInfo('user_data'); + + try { + $requestData['ok']($response); + } catch (Throwable $e) { + $requestData['error']($e); + } + + $queue[$_key] = null; + + gc_collect_cycles(); + } + + return $mapper->getObjects(); + } + /** * @inheritdoc */ diff --git a/src/Backends/Plex/Action/Import.php b/src/Backends/Plex/Action/Import.php index db70a3b4..727c914a 100644 --- a/src/Backends/Plex/Action/Import.php +++ b/src/Backends/Plex/Action/Import.php @@ -98,12 +98,13 @@ public function __invoke( ], ] ), + opts: $opts, ), action: $this->action ); } - protected function getLibraries(Context $context, Closure $handle, Closure $error): array + protected function getLibraries(Context $context, Closure $handle, Closure $error, array $opts = []): array { $segmentSize = (int)ag($context->options, Options::LIBRARY_SEGMENT, 1000); @@ -254,6 +255,8 @@ protected function getLibraries(Context $context, Closure $handle, Closure $erro $ignoreIds = array_map(fn($v) => (int)trim($v), explode(',', (string)$ignoreIds)); } + $limitLibraryId = ag($opts, Options::ONLY_LIBRARY_ID, null); + $requests = $total = []; $ignored = $unsupported = 0; @@ -261,6 +264,10 @@ protected function getLibraries(Context $context, Closure $handle, Closure $erro foreach ($listDirs as $section) { $key = (int)ag($section, 'key'); + if (null !== $limitLibraryId && $key !== (int)$limitLibraryId) { + continue; + } + $logContext = [ 'library' => [ 'id' => ag($section, 'key'), diff --git a/src/Backends/Plex/PlexClient.php b/src/Backends/Plex/PlexClient.php index 5d37ded7..9d555a0b 100644 --- a/src/Backends/Plex/PlexClient.php +++ b/src/Backends/Plex/PlexClient.php @@ -36,6 +36,7 @@ use App\Libs\Enums\Http\Status; use App\Libs\Exceptions\Backends\RuntimeException; use App\Libs\Exceptions\HttpException; +use App\Libs\Mappers\Import\ReadOnlyMapper; use App\Libs\Mappers\ImportInterface as iImport; use App\Libs\Options; use App\Libs\QueueRequests; @@ -50,6 +51,7 @@ use Symfony\Contracts\HttpClient\Exception\ServerExceptionInterface; use Symfony\Contracts\HttpClient\Exception\TransportExceptionInterface; use Symfony\Contracts\HttpClient\HttpClientInterface as iHttp; +use Throwable; /** * Class PlexClient @@ -417,6 +419,56 @@ public function getMetadata(string|int $id, array $opts = []): array return $response->response; } + /** + * @inheritdoc + */ + public function getLibraryContent(string|int $libraryId, array $opts = []): array + { + $mapper = Container::get(ReadOnlyMapper::class)->withOptions([]); + assert($mapper instanceof ReadOnlyMapper); + $mapper->asContainer(); + + $response = Container::get(Import::class)( + context: $this->context, + guid: $this->guid, + mapper: $mapper, + after: null, + opts: [ + Options::DISABLE_GUID => (bool)Config::get('episodes.disable.guid'), + Options::ONLY_LIBRARY_ID => $libraryId, + ...$opts, + ] + ); + + if ($response->hasError()) { + $this->logger->log($response->error->level(), $response->error->message, $response->error->context); + } + + if (false === $response->isSuccessful()) { + $this->throwError($response); + } + + if (null === ($queue = $response->response)) { + return []; + } + + foreach ($queue as $_key => $response) { + $requestData = $response->getInfo('user_data'); + + try { + $requestData['ok']($response); + } catch (Throwable $e) { + $requestData['error']($e); + } + + $queue[$_key] = null; + + gc_collect_cycles(); + } + + return $mapper->getObjects(); + } + /** * @inheritdoc */ diff --git a/src/Libs/Mappers/Import/MemoryMapper.php b/src/Libs/Mappers/Import/MemoryMapper.php index db5c2b31..bb7f5ebf 100644 --- a/src/Libs/Mappers/Import/MemoryMapper.php +++ b/src/Libs/Mappers/Import/MemoryMapper.php @@ -25,7 +25,7 @@ * * @implements iImport */ -final class MemoryMapper implements iImport +class MemoryMapper implements iImport { /** * @var string Local database GUID prefix. @@ -566,6 +566,7 @@ public function remove(iState $entity): bool /** * @inheritdoc + * @noinspection PhpRedundantCatchClauseInspection */ public function commit(): mixed { diff --git a/src/Libs/Mappers/Import/ReadOnlyMapper.php b/src/Libs/Mappers/Import/ReadOnlyMapper.php new file mode 100644 index 00000000..3f69e5e1 --- /dev/null +++ b/src/Libs/Mappers/Import/ReadOnlyMapper.php @@ -0,0 +1,76 @@ +isContainer = true; + } + + public function add(iState $entity, array $opts = []): MemoryMapper + { + if (false === $this->isContainer) { + return parent::add($entity, $opts); + } + $this->objects[] = $entity; + $pointer = array_key_last($this->objects); + $this->changed[$pointer] = $pointer; + $this->addPointers($this->objects[$pointer], $pointer); + + return $this; + } + + /** + * @inheritdoc + */ + public function remove(iState $entity): bool + { + if (false === ($pointer = $this->getPointer($entity))) { + return false; + } + + $this->removePointers($this->objects[$pointer]); + + if (null !== ($this->objects[$pointer] ?? null)) { + unset($this->objects[$pointer]); + } + + if (null !== ($this->changed[$pointer] ?? null)) { + unset($this->changed[$pointer]); + } + + return true; + } + + /** + * @inheritdoc + */ + public function commit(): array + { + $this->reset(); + + return [ + iState::TYPE_MOVIE => ['added' => 0, 'updated' => 0, 'failed' => 0], + iState::TYPE_EPISODE => ['added' => 0, 'updated' => 0, 'failed' => 0], + ]; + } + + public function __destruct() + { + // -- disabled autocommit. + } +} diff --git a/src/Libs/Options.php b/src/Libs/Options.php index c24f8219..58a41f78 100644 --- a/src/Libs/Options.php +++ b/src/Libs/Options.php @@ -40,6 +40,7 @@ final class Options public const string LOG_WRITER = 'LOG_WRITER'; public const string PLEX_USER_PIN = 'PLEX_USER_PIN'; public const string REQUEST_ID = 'REQUEST_ID'; + public const string ONLY_LIBRARY_ID = 'ONLY_LIBRARY_ID'; private function __construct() { From 9c1271a9d8be52ea794f9d5346e53692022aeff3 Mon Sep 17 00:00:00 2001 From: ArabCoders Date: Tue, 31 Dec 2024 21:49:18 +0300 Subject: [PATCH 2/6] Added id to useful command to ease communication for which command to run. --- frontend/pages/backends/index.vue | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/frontend/pages/backends/index.vue b/frontend/pages/backends/index.vue index 776b9e64..56774e7a 100644 --- a/frontend/pages/backends/index.vue +++ b/frontend/pages/backends/index.vue @@ -142,7 +142,7 @@ @@ -192,26 +192,31 @@ const selectedCommand = ref('') const usefulCommands = { export_now: { + id: 1, title: "Run normal export.", command: 'state:export -v -s {name}', state_key: 'export.enabled', }, import_now: { + id: 2, title: "Run normal import.", command: 'state:import -v -s {name}', state_key: 'import.enabled' }, force_export: { + id: 3, title: "Force export local play state to this backend.", command: 'state:export -fi -v -s {name}', state_key: 'export.enabled', }, backup_now: { + id: 4, title: "Backup this backend play state.", command: "state:backup -v -s {name} --file '{date}.manual_{name}.json'", state_key: 'import.enabled', }, metadata_only: { + id: 5, title: "Import this backend metadata.", command: "state:import -v --metadata-only -s {name}", state_key: 'import.enabled', From aeb3a3aeb1b63df3eb9e77a0a903efc71bdbe882 Mon Sep 17 00:00:00 2001 From: ArabCoders Date: Tue, 31 Dec 2024 22:12:38 +0300 Subject: [PATCH 3/6] Added new API endpoint to check for stale content from specific library. --- frontend/layouts/default.vue | 1 - .../pages/backend/[backend]/libraries.vue | 10 +- .../pages/backend/[backend]/stale/[id].vue | 206 ++++++++++++++++++ src/API/Backend/Stale.php | 119 ++++++++++ 4 files changed, 334 insertions(+), 2 deletions(-) create mode 100644 frontend/pages/backend/[backend]/stale/[id].vue create mode 100644 src/API/Backend/Stale.php diff --git a/frontend/layouts/default.vue b/frontend/layouts/default.vue index 3bcc5623..e9f8f134 100644 --- a/frontend/layouts/default.vue +++ b/frontend/layouts/default.vue @@ -336,7 +336,6 @@ - diff --git a/frontend/pages/backend/[backend]/libraries.vue b/frontend/pages/backend/[backend]/libraries.vue index cc34152a..6865fd7f 100644 --- a/frontend/pages/backend/[backend]/libraries.vue +++ b/frontend/pages/backend/[backend]/libraries.vue @@ -74,6 +74,14 @@ Ignore content from this library. + @@ -125,7 +133,7 @@ const loadContent = async () => { if (useRoute().name !== 'backend-backend-libraries') { return } - + if (200 !== response.status) { notification('error', 'Error', `${json.error.code}: ${json.error.message}`) return diff --git a/frontend/pages/backend/[backend]/stale/[id].vue b/frontend/pages/backend/[backend]/stale/[id].vue new file mode 100644 index 00000000..787636a6 --- /dev/null +++ b/frontend/pages/backend/[backend]/stale/[id].vue @@ -0,0 +1,206 @@ + + + diff --git a/src/API/Backend/Stale.php b/src/API/Backend/Stale.php new file mode 100644 index 00000000..af866715 --- /dev/null +++ b/src/API/Backend/Stale.php @@ -0,0 +1,119 @@ +getBackend(name: $name)) { + return api_error(r("Backend '{name}' not found.", ['name' => $name]), Status::NOT_FOUND); + } + + $params = DataUtil::fromArray($request->getQueryParams()); + + $backendOpts = $list = []; + + if ($params->get('timeout')) { + $backendOpts = ag_set($backendOpts, 'client.timeout', (float)$params->get('timeout')); + } + + try { + $client = $this->getClient(name: $name, config: $backendOpts); + } catch (RuntimeException $e) { + return api_error($e->getMessage(), Status::NOT_FOUND); + } + + $remote = cacheableItem( + 'remote-data-' . $name, + fn() => array_map(fn($item) => ag($item->getMetadata($item->via), iState::COLUMN_ID), + $client->getLibraryContent($id)) + , ignoreCache: (bool)$params->get('ignore', false) + ); + + $this->local->loadData(); + + $localCount = 0; + + foreach ($this->local->getObjects() as $entity) { + $backendData = $entity->getMetadata($name); + if (empty($backendData)) { + continue; + } + + if (null === ($libraryId = ag($backendData, iState::COLUMN_META_LIBRARY))) { + continue; + } + + if ((string)$libraryId !== (string)$id) { + continue; + } + + $localCount++; + + $localId = ag($backendData, iState::COLUMN_ID); + + if (true === in_array($localId, $remote, true)) { + continue; + } + + $list[] = $entity; + } + + $libraryInfo = []; + foreach ($client->listLibraries() as $library) { + if (null === ($libraryId = ag($library, 'id'))) { + continue; + } + if ((string)$id !== (string)$libraryId) { + continue; + } + $libraryInfo = $library; + break; + } + + return api_response(Status::OK, [ + 'backend' => [ + 'library' => $libraryInfo, + 'name' => $client->getContext()->backendName, + ], + 'counts' => [ + 'remote' => count($remote), + 'local' => $localCount, + 'stale' => count($list), + ], + 'items' => array_map(fn($item) => self::formatEntity($item), $list), + ]); + } +} From 97896ad58261b7ede695cb80c851189c90a2304a Mon Sep 17 00:00:00 2001 From: ArabCoders Date: Sat, 18 Jan 2025 02:01:26 +0300 Subject: [PATCH 4/6] Added initial support for multi-user play state sync. this feature still in alpha stage. --- FAQ.md | 55 +- README.md | 13 + config/config.php | 10 + config/env.spec.php | 2 +- src/Backends/Common/ClientInterface.php | 16 +- src/Backends/Emby/Action/UpdateState.php | 10 + src/Backends/Emby/EmbyClient.php | 20 +- src/Backends/Jellyfin/Action/UpdateState.php | 99 +++ src/Backends/Jellyfin/JellyfinClient.php | 30 +- src/Backends/Plex/Action/UpdateState.php | 91 +++ src/Backends/Plex/PlexClient.php | 15 + src/Commands/State/SyncCommand.php | 769 +++++++++++++++++++ src/Libs/Entity/StateEntity.php | 18 +- src/Libs/Entity/StateInterface.php | 10 + src/Libs/Mappers/Import/MemoryMapper.php | 45 +- src/Libs/Mappers/Import/NullMapper.php | 105 +++ 16 files changed, 1262 insertions(+), 46 deletions(-) create mode 100644 src/Backends/Emby/Action/UpdateState.php create mode 100644 src/Backends/Jellyfin/Action/UpdateState.php create mode 100644 src/Backends/Plex/Action/UpdateState.php create mode 100644 src/Commands/State/SyncCommand.php create mode 100644 src/Libs/Mappers/Import/NullMapper.php diff --git a/FAQ.md b/FAQ.md index d07d4e04..34de5c4b 100644 --- a/FAQ.md +++ b/FAQ.md @@ -211,22 +211,53 @@ database state back to the selected backend. ### Is there support for Multi-user setup? -No, The tool is designed to work for single user. However, It's possible to run container for each user. You can also -use single container for all users, however it's not really easy refer -to [issue #136](https://github.com/arabcoders/watchstate/issues/136). +There is a minimal support for multi-user setup via `state:sync` command. However, it still requires that you add your +backends as usual for single user setup and to use `state:sync` command, it's required that all backends have admin +access to be able to retrieve access-tokens for users. That means for Plex you need an admin token, and for +jellyfin/emby you need API key, not `user:password` limited access. -For `Jellyfin` and `Emby`, you can just generate new API tokens and link it to a user. +To get started using `state:sync` command, as mentioned before setup your backends as normal, then create a +`/config/config/mapper.yaml` file if your backends doesn't have the same user. for example -For Plex, You should use your admin token and by running the `config:add` command and selecting a user the tool will -attempt to generate a token for that user. +```yaml +- backend_name1: + name: "mike_jones" + options: { } + backend_name2: + name: "jones_mike" + options: { } + backend_name3: + name: "mikeJones" + options: { } + +- backend_name1: + name: "jiji_jones" + options: { } + backend_name2: + name: "jones_jiji" + options: { } + backend_name3: + name: "jijiJones" + options: { } +``` -> [!Note] -> If the tool fails to generate an access token for the user, you can run the following command to generate the access -> token manually. +This yaml file helps map your users accounts in the different backends, so the tool can sync the correct user data. -```bash -$ docker exec -ti console backend:users:list -s backend_name --with-tokens -``` +Then simply run `state:sync -v` it will generate the required tokens and match users data between the backends. +then sync the difference, Keep in mind that it will be slow and that's expected as it needs to do the same thing without +caching for all users servers and backends. it's recommended to not run this command frequently. as it's puts a lot of +load on the backends. By default, it will sync once every 3 hours. you can ofc change it to suit your needs. + +> [!NOTE] +> Known issues: + +* Currently, state:sync doesn't have a way of syncing plex users that has PIN enabled. +* Majority of the command flags aren't working or not implemented yet. + +> [!IMPORTANT] +> Please keep in mind the new command is still in alpha stage, so things will probably break. Please report any bugs +> you encounter. Also, please make sure to have a backup of your data before running the command. just in-case, +> while we did test it on our live data, it's always better to be safe than sorry. ---- diff --git a/README.md b/README.md index ffc4ffbb..cdcf720d 100644 --- a/README.md +++ b/README.md @@ -9,6 +9,19 @@ out of the box, this tool support `Jellyfin`, `Plex` and `Emby` media servers. ## Updates +### 2025-01-18 + +Due to popular demand, we finally have added the ability to sync all users data, however, it's limited to only +play state, no progress syncing implemented at this stage. This feature still in alpha expect bugs and issues. + +However our local tests shows that it's working as expected, but we need more testing to be sure. Please report any +issues you encounter. To enable this feature, you will see new task in the `Tasks` page called `Sync`. + +This task will sync all your users play state, However you need to have the backends added with admin token for plex and +API key for jellyfin and emby. Enable the task and let it run, it will sync all users play state. + +Please read the FAQ entry about it at [this link](FAQ.md#is-there-support-for-multi-user-setup). + ### 2024-12-30 We have removed the old environment variables `WS_CRON_PROGRESS` and `WS_CRON_PUSH` in favor of the new ones diff --git a/config/config.php b/config/config.php index 5493a617..f671e2fe 100644 --- a/config/config.php +++ b/config/config.php @@ -9,6 +9,7 @@ use App\Commands\State\BackupCommand; use App\Commands\State\ExportCommand; use App\Commands\State\ImportCommand; +use App\Commands\State\SyncCommand; use App\Commands\System\IndexCommand; use App\Commands\System\PruneCommand; use App\Libs\Mappers\Import\MemoryMapper; @@ -87,6 +88,7 @@ ]; $config['backends_file'] = fixPath(env('WS_BACKENDS_FILE', ag($config, 'path') . '/config/servers.yaml')); + $config['mapper_file'] = fixPath(env('WS_MAPPER_FILE', ag($config, 'path') . '/config/mapper.yaml')); date_default_timezone_set(ag($config, 'tz', 'UTC')); $logDateFormat = makeDate()->format('Ymd'); @@ -273,6 +275,14 @@ 'timer' => $checkTaskTimer((string)env('WS_CRON_EXPORT_AT', '30 */1 * * *'), '30 */1 * * *'), 'args' => env('WS_CRON_EXPORT_ARGS', '-v'), ], + SyncCommand::TASK_NAME => [ + 'command' => SyncCommand::ROUTE, + 'name' => SyncCommand::TASK_NAME, + 'info' => '[Alpha stage] Sync All users play state. Read the FAQ.', + 'enabled' => (bool)env('WS_CRON_SYNC', false), + 'timer' => $checkTaskTimer((string)env('WS_CRON_SYNC_AT', '9 */3 * * *'), '9 */3 * * *'), + 'args' => env('WS_CRON_SYNC_ARGS', '-v'), + ], BackupCommand::TASK_NAME => [ 'command' => BackupCommand::ROUTE, 'name' => BackupCommand::TASK_NAME, diff --git a/config/env.spec.php b/config/env.spec.php index d0f45d91..b692b5f2 100644 --- a/config/env.spec.php +++ b/config/env.spec.php @@ -196,7 +196,7 @@ }; // -- Do not forget to update the tasks list if you add a new task. - $tasks = ['import', 'export', 'backup', 'prune', 'indexes']; + $tasks = ['import', 'export', 'backup', 'prune', 'indexes', 'sync']; $task_env = [ [ 'key' => 'WS_CRON_{TASK}', diff --git a/src/Backends/Common/ClientInterface.php b/src/Backends/Common/ClientInterface.php index 083ba105..bb5ef187 100644 --- a/src/Backends/Common/ClientInterface.php +++ b/src/Backends/Common/ClientInterface.php @@ -17,7 +17,7 @@ use Psr\Http\Message\UriInterface as iUri; use Psr\Log\LoggerInterface as iLogger; use Symfony\Contracts\HttpClient\Exception\ExceptionInterface; -use Symfony\Contracts\HttpClient\ResponseInterface; +use Symfony\Contracts\HttpClient\ResponseInterface as iResponse; interface ClientInterface { @@ -85,7 +85,7 @@ public function parseWebhook(iRequest $request): iState; * @param iImport $mapper mapper to use. * @param iDate|null $after only import items after this date. * - * @return array responses. + * @return array responses. */ public function pull(iImport $mapper, iDate|null $after = null): array; @@ -96,7 +96,7 @@ public function pull(iImport $mapper, iDate|null $after = null): array; * @param iStream|null $writer writer to use. * @param array $opts options for backup. * - * @return array responses. + * @return array responses. */ public function backup(iImport $mapper, iStream|null $writer = null, array $opts = []): array; @@ -107,7 +107,7 @@ public function backup(iImport $mapper, iStream|null $writer = null, array $opts * @param QueueRequests $queue queue to use. * @param iDate|null $after only export items after this date. * - * @return array responses. + * @return array responses. */ public function export(iImport $mapper, QueueRequests $queue, iDate|null $after = null): array; @@ -325,4 +325,12 @@ public function generateAccessToken(string|int $identifier, string $password, ar * @return GuidInterface */ public function getGuid(): GuidInterface; + + /** + * Generate request to change the backend item play state. + * + * @param array $entities state entity. + * @param array $opts options. + */ + public function updateState(array $entities, QueueRequests $queue, array $opts = []): void; } diff --git a/src/Backends/Emby/Action/UpdateState.php b/src/Backends/Emby/Action/UpdateState.php new file mode 100644 index 00000000..5fecdd8b --- /dev/null +++ b/src/Backends/Emby/Action/UpdateState.php @@ -0,0 +1,10 @@ +context, + entities: $entities, + queue: $queue, + opts: $opts + ); + + if ($response->hasError()) { + $this->logger->log($response->error->level(), $response->error->message, $response->error->context); + } + } + /** * @inheritdoc */ diff --git a/src/Backends/Jellyfin/Action/UpdateState.php b/src/Backends/Jellyfin/Action/UpdateState.php new file mode 100644 index 00000000..91cd33cd --- /dev/null +++ b/src/Backends/Jellyfin/Action/UpdateState.php @@ -0,0 +1,99 @@ + $entities State instance. + * @param QueueRequests $queue QueueRequests instance. + * @param array $opts optional options. + * + * @return Response + */ + public function __invoke(Context $context, array $entities, QueueRequests $queue, array $opts = []): Response + { + return $this->tryResponse( + context: $context, + fn: function () use ($context, $entities, $opts, $queue) { + foreach ($entities as $entity) { + $meta = $entity->getMetadata($context->backendName); + if (count($meta) < 1) { + continue; + } + + if ($entity->isWatched() === (bool)ag($meta, iState::COLUMN_WATCHED)) { + continue; + } + + if (null === ($itemId = ag($meta, iState::COLUMN_ID))) { + continue; + } + + $url = $context->backendUrl->withPath( + r('/Users/{user_id}/PlayedItems/{item_id}', [ + 'user_id' => $context->backendUser, + 'item_id' => $itemId, + ]) + ); + + if ($context->clientName === JellyfinClient::CLIENT_NAME) { + $url = $url->withQuery( + http_build_query([ + 'DatePlayed' => makeDate($entity->updated)->format(Date::ATOM) + ]) + ); + } + + $queue->add( + $this->http->request( + method: $entity->isWatched() ? 'POST' : 'DELETE', + url: (string)$url, + options: $context->backendHeaders + [ + 'user_data' => [ + 'context' => [ + 'backend' => $context->backendName, + 'play_state' => $entity->isWatched() ? 'played' : 'unplayed', + 'item' => [ + 'id' => $itemId, + 'title' => $entity->getName(), + 'type' => $entity->type == iState::TYPE_EPISODE ? 'episode' : 'movie', + 'state' => $entity->isWatched() ? 'played' : 'unplayed', + ], + 'url' => (string)$url, + ] + ], + ] + ) + ); + } + + return new Response(status: true); + }, + action: $this->action + ); + } +} diff --git a/src/Backends/Jellyfin/JellyfinClient.php b/src/Backends/Jellyfin/JellyfinClient.php index 4ca15f72..0276e790 100644 --- a/src/Backends/Jellyfin/JellyfinClient.php +++ b/src/Backends/Jellyfin/JellyfinClient.php @@ -31,6 +31,7 @@ use App\Backends\Jellyfin\Action\SearchId; use App\Backends\Jellyfin\Action\SearchQuery; use App\Backends\Jellyfin\Action\ToEntity; +use App\Backends\Jellyfin\Action\UpdateState; use App\Libs\Config; use App\Libs\Container; use App\Libs\Entity\StateInterface as iState; @@ -43,8 +44,8 @@ use App\Libs\QueueRequests; use App\Libs\Uri; use DateTimeInterface as iDate; -use Psr\Http\Message\ServerRequestInterface; -use Psr\Http\Message\StreamInterface; +use Psr\Http\Message\ServerRequestInterface as iRequest; +use Psr\Http\Message\StreamInterface as iStream; use Psr\Http\Message\UriInterface; use Psr\Log\LoggerInterface as iLogger; use Throwable; @@ -205,7 +206,7 @@ public function setLogger(iLogger $logger): self /** * @inheritdoc */ - public function processRequest(ServerRequestInterface $request, array $opts = []): ServerRequestInterface + public function processRequest(iRequest $request, array $opts = []): iRequest { $response = Container::get(InspectRequest::class)(context: $this->context, request: $request); @@ -219,7 +220,7 @@ public function processRequest(ServerRequestInterface $request, array $opts = [] /** * @inheritdoc */ - public function parseWebhook(ServerRequestInterface $request): iState + public function parseWebhook(iRequest $request): iState { $response = Container::get(ParseWebhook::class)( context: $this->context, @@ -270,7 +271,7 @@ public function pull(iImport $mapper, iDate|null $after = null): array /** * @inheritdoc */ - public function backup(iImport $mapper, StreamInterface|null $writer = null, array $opts = []): array + public function backup(iImport $mapper, iStream|null $writer = null, array $opts = []): array { $response = Container::get(Backup::class)( context: $this->context, @@ -670,7 +671,7 @@ public function getVersion(array $opts = []): string /** * @inheritdoc */ - public function fromRequest(array $config, ServerRequestInterface $request): array + public function fromRequest(array $config, iRequest $request): array { return $config; } @@ -683,6 +684,23 @@ public function validateContext(Context $context): bool return Container::get(JellyfinValidateContext::class)($context); } + /** + * @inheritdoc + */ + public function updateState(array $entities, QueueRequests $queue, array $opts = []): void + { + $response = Container::get(UpdateState::class)( + context: $this->context, + entities: $entities, + queue: $queue, + opts: $opts + ); + + if ($response->hasError()) { + $this->logger->log($response->error->level(), $response->error->message, $response->error->context); + } + } + /** * @inheritdoc */ diff --git a/src/Backends/Plex/Action/UpdateState.php b/src/Backends/Plex/Action/UpdateState.php new file mode 100644 index 00000000..32c7597b --- /dev/null +++ b/src/Backends/Plex/Action/UpdateState.php @@ -0,0 +1,91 @@ + $entities State instance. + * @param QueueRequests $queue QueueRequests instance. + * @param array $opts optional options. + * + * @return Response + */ + public function __invoke(Context $context, array $entities, QueueRequests $queue, array $opts = []): Response + { + return $this->tryResponse( + context: $context, + fn: function () use ($context, $entities, $opts, $queue) { + foreach ($entities as $entity) { + $meta = $entity->getMetadata($context->backendName); + if (count($meta) < 1) { + continue; + } + + if (null === ($itemId = ag($meta, iState::COLUMN_ID))) { + continue; + } + + $itemBackendState = (bool)ag($meta, iState::COLUMN_WATCHED); + + if ($entity->isWatched() === $itemBackendState) { + continue; + } + + $url = $context->backendUrl->withPath($entity->isWatched() ? '/:/scrobble' : '/:/unscrobble') + ->withQuery( + http_build_query([ + 'identifier' => 'com.plexapp.plugins.library', + 'key' => $itemId, + ]) + ); + + $queue->add( + $this->http->request( + method: 'GET', + url: (string)$url, + options: $context->backendHeaders + [ + 'user_data' => [ + 'context' => [ + 'backend' => $context->backendName, + 'play_state' => $entity->isWatched() ? 'played' : 'unplayed', + 'item' => [ + 'id' => $itemId, + 'title' => $entity->getName(), + 'type' => $entity->type == iState::TYPE_EPISODE ? 'episode' : 'movie', + 'state' => $entity->isWatched() ? 'played' : 'unplayed', + ], + ] + ], + ] + ) + ); + } + + return new Response(status: true); + }, + action: $this->action + ); + } +} diff --git a/src/Backends/Plex/PlexClient.php b/src/Backends/Plex/PlexClient.php index 9d555a0b..d7e7c868 100644 --- a/src/Backends/Plex/PlexClient.php +++ b/src/Backends/Plex/PlexClient.php @@ -29,6 +29,7 @@ use App\Backends\Plex\Action\SearchId; use App\Backends\Plex\Action\SearchQuery; use App\Backends\Plex\Action\ToEntity; +use App\Backends\Plex\Action\UpdateState; use App\Libs\Config; use App\Libs\Container; use App\Libs\DataUtil; @@ -687,6 +688,20 @@ public function validateContext(Context $context): bool return Container::get(PlexValidateContext::class)($context); } + public function updateState(array $entities, QueueRequests $queue, array $opts = []): void + { + $response = Container::get(UpdateState::class)( + context: $this->context, + entities: $entities, + queue: $queue, + opts: $opts + ); + + if ($response->hasError()) { + $this->logger->log($response->error->level(), $response->error->message, $response->error->context); + } + } + /** * @inheritdoc */ diff --git a/src/Commands/State/SyncCommand.php b/src/Commands/State/SyncCommand.php new file mode 100644 index 00000000..32bf7388 --- /dev/null +++ b/src/Commands/State/SyncCommand.php @@ -0,0 +1,769 @@ +mapper->setLogger(new NullLogger()); + parent::__construct(); + } + + /** + * Configure the command. + */ + protected function configure(): void + { + $this->setName(self::ROUTE) + ->setDescription('Sync All users play state to backends.') + ->addOption('force-full', 'f', InputOption::VALUE_NONE, 'Force full export. Ignore last export date.') + ->addOption('dry-run', null, InputOption::VALUE_NONE, 'Do not commit changes to backends.') + ->addOption('timeout', null, InputOption::VALUE_REQUIRED, 'Set request timeout in seconds.') + ->addOption( + 'select-backend', + 's', + InputOption::VALUE_IS_ARRAY | InputOption::VALUE_OPTIONAL, + 'Select backend.' + ) + ->addOption('exclude', null, InputOption::VALUE_NONE, 'Inverse --select-backend logic.') + ->addOption('ignore-date', 'i', InputOption::VALUE_NONE, 'Ignore date comparison.') + ->addOption('logfile', null, InputOption::VALUE_REQUIRED, 'Save console output to file.') + ->setHelp( + r( + <<[ FAQ ] + ------- + + Will this work with limited tokens? + + No, This requires admin token for plex backend, and API keys for jellyfin/emby. + We need the admin token for plex to generate user tokens for each user, and we need the API keys + for jellyfin/emby to get the user list and update their play state. + + # How does this sync operation mode work? + + It works by first, getting all users from all backends, and trying to match them by name, + once we build a list of users that are matched, then we basically run the import/export for each user + using in memory storage, it should not have any impact on the real database and cache. + + You can help the matching by using the mapper file, which is a simple YAML file that maps users from one + backend to another, this is useful when the usernames are different or when you want to merge users from + different backends into one user. + + Example of a mapper.yaml file: + + - backend1: "mike_james" + backend2: "james_mike" + + - backend1: "john_doe" + backend2: "doe_john" + + HELP, + [ + 'cmd' => trim(commandContext()), + 'route' => self::ROUTE, + + ] + ) + ); + } + + /** + * Make sure the command is not running in parallel. + * + * @param iInput $input The input object containing the command data. + * @param iOutput $output The output object for displaying command output. + * + * @return int The exit code of the command execution. + */ + protected function runCommand(iInput $input, iOutput $output): int + { + return $this->single(fn(): int => $this->process($input, $output), $output); + } + + /** + * Process the command by pulling and comparing status and then pushing. + * + * @param iInput $input + * @param iOutput $output + * @return int + */ + protected function process(iInput $input, iOutput $output): int + { + if (null !== ($logfile = $input->getOption('logfile')) && true === ($this->logger instanceof Logger)) { + $this->logger->setHandlers([ + $this->suppressor->withHandler(new StreamLogHandler(new Stream($logfile, 'w'), $output)) + ]); + } + + $mapFile = Config::get('mapper_file'); + if (file_exists($mapFile) && filesize($mapFile) > 10) { + $map = ConfigFile::open(Config::get('mapper_file'), 'yaml'); + $this->mapping = $map->getAll(); + } + + $configFile = ConfigFile::open(Config::get('backends_file'), 'yaml'); + $configFile->setLogger($this->logger); + + $backends = []; + $selected = $input->getOption('select-backend'); + $isCustom = !empty($selected) && count($selected) > 0; + $supported = Config::get('supported', []); + + if (true === $input->getOption('dry-run')) { + $this->logger->notice('Dry run mode. No changes will be committed to backends.'); + } + + foreach ($configFile->getAll() as $backendName => $backend) { + $type = strtolower(ag($backend, 'type', 'unknown')); + + if ($isCustom && $input->getOption('exclude') === in_array($backendName, $selected)) { + $this->logger->info("SYSTEM: Ignoring '{backend}' as requested by [-s, --select-backend].", [ + 'backend' => $backendName + ]); + continue; + } + + if (true !== (bool)ag($backend, 'export.enabled')) { + $this->logger->info("SYSTEM: Ignoring '{backend}' as the backend has export disabled.", [ + 'backend' => $backendName + ]); + continue; + } + + if (!isset($supported[$type])) { + $this->logger->error( + "SYSTEM: Ignoring '{backend}' due to unexpected type '{type}'. Expecting '{types}'.", + [ + 'type' => $type, + 'backend' => $backendName, + 'types' => implode(', ', array_keys($supported)), + ] + ); + continue; + } + + if (null === ($url = ag($backend, 'url')) || false === isValidURL($url)) { + $this->logger->error("SYSTEM: Ignoring '{backend}' due to invalid URL. '{url}'.", [ + 'url' => $url ?? 'None', + 'backend' => $backendName, + ]); + continue; + } + + $backend['name'] = $backendName; + $backends[$backendName] = $backend; + } + + if (empty($backends)) { + $this->logger->warning('No backends were found.'); + return self::FAILURE; + } + + foreach ($backends as &$backend) { + if (null === ($name = ag($backend, 'name'))) { + continue; + } + + $opts = ag($backend, 'options', []); + + if ($input->getOption('ignore-date')) { + $opts[Options::IGNORE_DATE] = true; + } + + if ($input->getOption('trace')) { + $opts[Options::DEBUG_TRACE] = true; + } + + if ($input->getOption('dry-run')) { + $opts[Options::DRY_RUN] = true; + } + + if ($input->getOption('timeout')) { + $opts['client']['timeout'] = $input->getOption('timeout'); + } + + $backend['options'] = $opts; + $backend['class'] = $this->getBackend($name, $backend)->setLogger($this->logger); + } + + unset($backend); + + $this->logger->notice("SYSTEM: Getting users list from '{backends}'.", [ + 'backends' => join(', ', array_map(fn($backend) => $backend['name'], $backends)) + ] + ); + + $users = []; + + foreach ($backends as $backend) { + /** @var iClient $client */ + $client = ag($backend, 'class'); + assert($backend instanceof iClient); + $this->logger->info("SYSTEM: Getting users from '{backend}'.", [ + 'backend' => $client->getContext()->backendName + ]); + try { + foreach ($client->getUsersList(['tokens' => true]) as $user) { + $info = $backend; + $info['token'] = ag($user, 'token', ag($backend, 'token')); + $info['user'] = ag($user, 'id', ag($info, 'user')); + $info['backendName'] = r("{backend}_{user}", [ + 'backend' => ag($backend, 'name'), + 'user' => ag($user, 'name'), + ]); + $info['displayName'] = ag($user, 'name'); + $info = ag_delete($info, 'options.' . Options::PLEX_USER_PIN); + $info = ag_delete($info, 'options.' . Options::ADMIN_TOKEN); + + unset($info['class']); + $user['backend'] = ag($backend, 'name'); + $user['client_data'] = $info; + $users[] = $user; + } + } catch (Throwable $e) { + $this->logger->error( + "Exception '{error.kind}' was thrown unhandled during '{client}: {backend}' get users list. '{error.message}' at '{error.file}:{error.line}'.", + [ + 'backend' => $client->getContext()->backendName, + 'client' => $client->getContext()->clientName, + 'error' => [ + 'kind' => $e::class, + 'line' => $e->getLine(), + 'message' => $e->getMessage(), + 'file' => after($e->getFile(), ROOT_PATH), + ], + 'exception' => [ + 'file' => $e->getFile(), + 'line' => $e->getLine(), + 'kind' => get_class($e), + 'message' => $e->getMessage(), + ], + ] + ); + } + } + + $users = $this->generate_users_list($users, $this->mapping); + + if (count($users) < 1) { + $this->logger->warning('No users were found.'); + return self::FAILURE; + } + + $this->logger->notice("SYSTEM: User matching results {results}.", [ + 'results' => arrayToString($this->usersList($users)), + ]); + + foreach (array_reverse($users) as $user) { + $this->queue->reset(); + $this->mapper->reset(); + + $list = []; + $displayName = null; + + foreach (ag($user, 'backends', []) as $backend) { + $name = ag($backend, 'client_data.backendName'); + $clientData = ag($backend, 'client_data'); + $clientData['name'] = $name; + $clientData['class'] = makeBackend($clientData, $name)->setLogger($this->logger); + $list[$name] = $clientData; + $displayName = ag($backend, 'client_data.displayName', '??'); + } + + $start = makeDate(); + $this->logger->notice("SYSTEM: Syncing user '{user}' -> '{list}'.", [ + 'user' => $displayName, + 'list' => join(', ', array_keys($list)), + 'started' => $start, + ]); + + $this->handleImport($displayName, $list); + + $changes = $this->mapper->computeChanges(array_keys($list)); + + foreach ($changes as $b => $changed) { + $count = count($changed); + $this->logger->notice("SYSTEM: Changes detected for '{name}: {backend}' are '{changes}'.", [ + 'name' => $displayName, + 'backend' => $b, + 'changes' => $count, + 'items' => array_map( + fn(iState $i) => [ + 'title' => $i->getName(), + 'state' => $i->isWatched() ? 'played' : 'unplayed', + 'meta' => $i->isSynced(array_keys($list)), + ], + $changed + ) + ]); + + if ($count >= 1) { + /** @var iClient $client */ + $client = $list[$b]['class']; + $client->updateState($changed, $this->queue); + } + } + + $this->handleExport($displayName); + + $end = makeDate(); + $this->logger->notice("SYSTEM: Completed syncing user '{name}' -> '{list}' in '{time.duration}'s", [ + 'name' => $displayName, + 'list' => join(', ', array_keys($list)), + 'time' => [ + 'start' => $start, + 'end' => $end, + 'duration' => $end->getTimestamp() - $start->getTimestamp(), + ], + 'memory' => [ + 'now' => getMemoryUsage(), + 'peak' => getPeakMemoryUsage(), + ], + ]); + exit(1); + } + + return self::SUCCESS; + } + + protected function handleImport(string $name, array $backends): void + { + /** @var array $queue */ + $queue = []; + + foreach ($backends as $backend) { + /** @var iClient $client */ + $client = ag($backend, 'class'); + array_push($queue, ...$client->pull($this->mapper)); + } + + $start = makeDate(); + $this->logger->notice("SYSTEM: Waiting on '{total}' requests for import '{name}' data.", [ + 'name' => $name, + 'total' => number_format(count($queue)), + 'time' => [ + 'start' => $start, + ], + 'memory' => [ + 'now' => getMemoryUsage(), + 'peak' => getPeakMemoryUsage(), + ], + ]); + + foreach ($queue as $_key => $response) { + $requestData = $response->getInfo('user_data'); + + try { + $requestData['ok']($response); + } catch (Throwable $e) { + $requestData['error']($e); + } + + $queue[$_key] = null; + + gc_collect_cycles(); + } + + $end = makeDate(); + $this->logger->notice( + "SYSTEM: Completed waiting on '{total}' requests in '{time.duration}'s for importing '{name}' data. Parsed '{responses.size}' of data.", + [ + 'name' => $name, + 'total' => number_format(count($queue)), + 'time' => [ + 'start' => $start, + 'end' => $end, + 'duration' => $end->getTimestamp() - $start->getTimestamp(), + ], + 'memory' => [ + 'now' => getMemoryUsage(), + 'peak' => getPeakMemoryUsage(), + ], + 'responses' => [ + 'size' => fsize((int)Message::get('response.size', 0)), + ], + ] + ); + + Message::add('response.size', 0); + } + + protected function handleExport(string $name): void + { + $total = count($this->queue->getQueue()); + if ($total < 1) { + $this->logger->notice("SYSTEM: No play state changes detected for '{name}' backends.", ['name' => $name]); + return; + } + + $this->logger->notice("SYSTEM: Sending '{total}' change play state requests for '{name}'.", [ + 'name' => $name, + 'total' => $total + ]); + + foreach ($this->queue->getQueue() as $response) { + $context = ag($response->getInfo('user_data'), 'context', []); + + try { + if (200 !== ($statusCode = $response->getStatusCode())) { + $this->logger->error( + "Request to change '{name}: {backend}' '{item.title}' play state returned with unexpected '{status_code}' status code.", + [ + 'name' => $name, + 'status_code' => $statusCode, + ...$context, + ], + ); + continue; + } + + $this->logger->notice("Marked '{name}: {backend}' '{item.title}' as '{play_state}'.", [ + 'name' => $name, + ...$context + ]); + } catch (Throwable $e) { + $this->logger->error( + message: "Exception '{error.kind}' was thrown unhandled during '{name}: {backend}' request to change play state of {item.type} '{item.title}'. '{error.message}' at '{error.file}:{error.line}'.", + context: [ + 'name' => $name, + 'error' => [ + 'kind' => $e::class, + 'line' => $e->getLine(), + 'message' => $e->getMessage(), + 'file' => after($e->getFile(), ROOT_PATH), + ], + ...$context, + 'exception' => [ + 'file' => $e->getFile(), + 'line' => $e->getLine(), + 'kind' => get_class($e), + 'message' => $e->getMessage(), + ], + ] + ); + } + } + + $this->logger->notice("SYSTEM: Sent '{total}' change play state requests for '{name}'.", [ + 'name' => $name, + 'total' => $total + ]); + } + + /** + * Generate a list of users that are matched across all backends. + * + * @param array $users The list of users from all backends. + * @param array{string: array{string: string, options: array}} $map The map of users to match. + * + * @return array{name: string, backends: array>}[] The list of matched users. + */ + private function generate_users_list(array $users, array $map = []): array + { + $allBackends = []; + foreach ($users as $u) { + if (!in_array($u['backend'], $allBackends, true)) { + $allBackends[] = $u['backend']; + } + } + + // Build a lookup: $usersBy[backend][lowercased_name] = userObject + $usersBy = []; + foreach ($users as $user) { + $backend = $user['backend']; + $nameLower = strtolower($user['name']); + + if (!isset($usersBy[$backend])) { + $usersBy[$backend] = []; + } + $usersBy[$backend][$nameLower] = $user; + } + + $results = []; + + // Track used combos: array of [backend, nameLower]. + $used = []; + + // Helper: check if a (backend, nameLower) is already used. + $alreadyUsed = fn(string $b, string $n): bool => in_array([$b, $n], $used, true); + + /** + * Build a "unified" row from matched users across backends. + * - $backendDict example: [ 'backend1' => userObj, 'backend2' => userObj, ... ] + * - Picks a 'name' by "most frequent name" logic (with tie fallback). + * + * Returns an array shaped like: + * + * return [ + * 'name' => 'something', + * 'backends' => [ + * 'backend1' => userObj, + * 'backend2' => userObj, + * ... + * ] + * ] + * + */ + $buildUnifiedRow = function (array $backendDict) use ($allBackends): array { + // Collect the names in the order of $allBackends for tie-breaking. + $names = []; + foreach ($allBackends as $b) { + if (isset($backendDict[$b])) { + $names[] = $backendDict[$b]['name']; + } + } + + // Tally frequencies + $freq = []; + foreach ($names as $n) { + if (!isset($freq[$n])) { + $freq[$n] = 0; + } + $freq[$n]++; + } + + // Decide a final 'name' + if (empty($freq)) { + $finalName = 'unknown'; + } else { + $max = max($freq); + $candidates = array_keys(array_filter($freq, fn($count) => $count === $max)); + + if (1 === count($candidates)) { + $finalName = $candidates[0]; + } else { + // Tie => pick the first from $names that’s in $candidates + $finalName = null; + foreach ($names as $n) { + if (in_array($n, $candidates, true)) { + $finalName = $n; + break; + } + } + if (!$finalName) { + $finalName = 'unknown'; + } + } + } + + // Build final row: "name" + sub-array "backends" + $row = [ + 'name' => $finalName, + 'backends' => [], + ]; + + // Fill 'backends' + foreach ($allBackends as $b) { + if (isset($backendDict[$b])) { + $row['backends'][$b] = $backendDict[$b]; + } + } + + return $row; + }; + + // Main logic: For each backend and each user in that backend, unify them if we find a match in ≥2 backends. + // We do map-based matching first, then direct-name matching. + foreach ($allBackends as $backend) { + if (!isset($usersBy[$backend])) { + continue; + } + + // For each user in this backend + foreach ($usersBy[$backend] as $nameLower => $userObj) { + // Skip if already used + if ($alreadyUsed($backend, $nameLower)) { + continue; + } + + // Map-based matching first + $matchedMapEntry = null; + foreach ($map as $mapRow) { + if (isset($mapRow[$backend]['name']) && strtolower($mapRow[$backend]['name']) === $nameLower) { + $matchedMapEntry = $mapRow; + break; + } + } + + if ($matchedMapEntry) { + // Build mapMatch from the map row. + $mapMatch = [$backend => $userObj]; + + // Gather all the other backends from the map + foreach ($allBackends as $otherBackend) { + if ($otherBackend === $backend) { + continue; + } + if (isset($matchedMapEntry[$otherBackend]['name'])) { + $mappedNameLower = strtolower($matchedMapEntry[$otherBackend]['name']); + if (isset($usersBy[$otherBackend][$mappedNameLower])) { + $mapMatch[$otherBackend] = $usersBy[$otherBackend][$mappedNameLower]; + } + } + } + + // If we matched ≥ 2 backends, unify them + if (count($mapMatch) >= 2) { + // --- MERGE map-based "options" into client_data => options, if any --- + foreach ($mapMatch as $b => &$matchedUser) { + // If the map entry has an 'options' array for this backend, + // merge it into $matchedUser['client_data']['options']. + if (isset($matchedMapEntry[$b]['options']) && is_array($matchedMapEntry[$b]['options'])) { + $mapOptions = $matchedMapEntry[$b]['options']; + + // Ensure $matchedUser['client_data'] is an array + if (!isset($matchedUser['client_data']) || !is_array($matchedUser['client_data'])) { + $matchedUser['client_data'] = []; + } + + // Ensure $matchedUser['client_data']['options'] is an array + if (!isset($matchedUser['client_data']['options']) || !is_array( + $matchedUser['client_data']['options'] + )) { + $matchedUser['client_data']['options'] = []; + } + + // Merge the map's options + $matchedUser['client_data']['options'] = array_replace_recursive( + $matchedUser['client_data']['options'], + $mapOptions + ); + } + } + unset($matchedUser); // break reference from the loop + + // Build final row + $results[] = $buildUnifiedRow($mapMatch); + + // Mark & remove from $usersBy + foreach ($mapMatch as $b => $mu) { + $nm = strtolower($mu['name']); + $used[] = [$b, $nm]; + unset($usersBy[$b][$nm]); + } + continue; + } else { + $this->logger->error("No partial fallback match via map for '{backend}: {user}'", [ + 'backend' => $userObj['backend'], + 'user' => $userObj['name'], + ]); + } + } + + // Direct-name matching if map fails + $directMatch = [$backend => $userObj]; + foreach ($allBackends as $otherBackend) { + if ($otherBackend === $backend) { + continue; + } + // Same name => direct match + if (isset($usersBy[$otherBackend][$nameLower])) { + $directMatch[$otherBackend] = $usersBy[$otherBackend][$nameLower]; + } + } + + // If direct matched ≥ 2 backends, unify + if (count($directMatch) >= 2) { + // No map "options" to merge here + $results[] = $buildUnifiedRow($directMatch); + + // Mark & remove them from $usersBy + foreach ($directMatch as $b => $matchedUser) { + $nm = strtolower($matchedUser['name']); + $used[] = [$b, $nm]; + unset($usersBy[$b][$nm]); + } + continue; + } + + // If neither map nor direct matched for ≥2 + $this->logger->error("Cannot match user '{backend}: {user}' in any map row or direct match.", [ + 'backend' => $userObj['backend'], + 'user' => $userObj['name'] + ]); + } + } + + return $results; + } + + private function usersList(array $list): array + { + $chunks = []; + + foreach ($list as $row) { + $name = $row['name'] ?? 'unknown'; + + $pairs = []; + if (!empty($row['backends']) && is_array($row['backends'])) { + foreach ($row['backends'] as $backendName => $backendData) { + if (isset($backendData['name'])) { + $pairs[] = r("{name}@{backend}", ['backend' => $backendName, 'name' => $backendData['name']]); + } + } + } + + $chunks[] = r("{name}: {pairs}", ['name' => $name, 'pairs' => implode(', ', $pairs)]); + } + + return $chunks; + } +} diff --git a/src/Libs/Entity/StateEntity.php b/src/Libs/Entity/StateEntity.php index 8e774c1a..65b25b76 100644 --- a/src/Libs/Entity/StateEntity.php +++ b/src/Libs/Entity/StateEntity.php @@ -15,7 +15,7 @@ * Represents an metadata as entity. * * @implements iState - * @uses LoggerAwareTrait + * @implements LoggerAwareTrait */ final class StateEntity implements iState { @@ -698,6 +698,22 @@ public function hasContext(string $key): bool return ag_exists($this->context, $key); } + public function isSynced(array $backends): array + { + $match = []; + + + foreach ($backends as $backend) { + if (null === ag($this->metadata, $backend)) { + $match[$backend] = null; + continue; + } + $match[$backend] = $this->isWatched() === (bool)ag($this->metadata[$backend], iState::COLUMN_WATCHED, 0); + } + + return $match; + } + /** * Checks if the value of a given key in the entity object is equal to the corresponding value in the current object. * Some keys are special and require special logic to compare. For example, the updated and watched keys are special diff --git a/src/Libs/Entity/StateInterface.php b/src/Libs/Entity/StateInterface.php index 993cfa56..16f2db1a 100644 --- a/src/Libs/Entity/StateInterface.php +++ b/src/Libs/Entity/StateInterface.php @@ -422,4 +422,14 @@ public function getMeta(string $key, mixed $default = null): mixed; * @return bool Return true if the entity has contextual data related to the key. */ public function hasContext(string $key): bool; + + /** + * Check whether the entity play state is synced with the backends. + * + * @param array $backends List of backends to check. + * + * @return array{string: bool|null} Return true if the entity is synced with the backend. or false if not, or null if the backend has no metadata. + */ + public function isSynced(array $backends): array; + } diff --git a/src/Libs/Mappers/Import/MemoryMapper.php b/src/Libs/Mappers/Import/MemoryMapper.php index bb7f5ebf..ed567239 100644 --- a/src/Libs/Mappers/Import/MemoryMapper.php +++ b/src/Libs/Mappers/Import/MemoryMapper.php @@ -116,7 +116,7 @@ public function loadData(iDate|null $date = null): self $this->addPointers($this->objects[$pointer], $pointer); } - $this->logger->info("MAPPER: Preloaded '{pointers}' pointers, and '{objects}' objects into memory.", [ + $this->logger->info("MemoryMapper: Preloaded '{pointers}' pointers, and '{objects}' objects into memory.", [ 'pointers' => number_format(count($this->pointers)), 'objects' => number_format(count($this->objects)), ]); @@ -133,12 +133,12 @@ public function loadData(iDate|null $date = null): self * * @return self */ - private function addNewItem(iState $entity, array $opts = []): self + protected function addNewItem(iState $entity, array $opts = []): self { if (true === (bool)ag($opts, Options::IMPORT_METADATA_ONLY)) { Message::increment("{$entity->via}.{$entity->type}.failed"); $this->logger->notice( - "MAPPER: Ignoring '{backend}' '{title}'. Does not exist in database. And backend set as metadata source only.", + "MemoryMapper: Ignoring '{backend}' '{title}'. Does not exist in database. And backend set as metadata source only.", [ 'metaOnly' => true, 'backend' => $entity->via, @@ -178,7 +178,7 @@ private function addNewItem(iState $entity, array $opts = []): self ]; } - $this->logger->notice("MAPPER: '{backend}' added '{title}' as new item.", [ + $this->logger->notice("MemoryMapper: '{backend}' added '{title}' as new item.", [ 'backend' => $entity->via, 'title' => $entity->getName(), true === $this->inTraceMode() ? 'trace' : 'metadata' => $data, @@ -197,7 +197,7 @@ private function addNewItem(iState $entity, array $opts = []): self * * @return self */ - private function handleTainted(string|int $pointer, iState $cloned, iState $entity, array $opts = []): self + protected function handleTainted(string|int $pointer, iState $cloned, iState $entity, array $opts = []): self { $keys = [iState::COLUMN_META_DATA]; @@ -215,7 +215,7 @@ private function handleTainted(string|int $pointer, iState $cloned, iState $enti $changes = $this->objects[$pointer]->diff(fields: $keys); if (count($changes) >= 1) { - $this->logger->notice("MAPPER: '{backend}' updated '{title}' metadata.", [ + $this->logger->notice("MemoryMapper: '{backend}' updated '{title}' metadata.", [ 'id' => $cloned->id, 'backend' => $entity->via, 'title' => $cloned->getName(), @@ -240,7 +240,7 @@ private function handleTainted(string|int $pointer, iState $cloned, iState $enti } $this->logger->notice( - "MAPPER: '{backend}' item '{id}: {title}' is marked as '{state}' vs local state '{local_state}', However due to the following reason '{reasons}' it was not considered as valid state.", + "MemoryMapper: '{backend}' item '{id}: {title}' is marked as '{state}' vs local state '{local_state}', However due to the following reason '{reasons}' it was not considered as valid state.", [ 'id' => $this->objects[$pointer]->id, 'backend' => $entity->via, @@ -255,7 +255,7 @@ private function handleTainted(string|int $pointer, iState $cloned, iState $enti } if (true === $this->inTraceMode()) { - $this->logger->info("MAPPER: '{backend}' '{title}' No metadata changes detected.", [ + $this->logger->info("MemoryMapper: '{backend}' '{title}' No metadata changes detected.", [ 'id' => $cloned->id, 'backend' => $entity->via, 'title' => $cloned->getName(), @@ -265,7 +265,7 @@ private function handleTainted(string|int $pointer, iState $cloned, iState $enti return $this; } - private function handleOldEntity(string|int $pointer, iState $cloned, iState $entity, array $opts = []): self + protected function handleOldEntity(string|int $pointer, iState $cloned, iState $entity, array $opts = []): self { $keys = [iState::COLUMN_META_DATA]; @@ -284,7 +284,7 @@ private function handleOldEntity(string|int $pointer, iState $cloned, iState $en ); if (count($changes) >= 1) { - $this->logger->notice("MAPPER: '{backend}' marked '{title}' as 'unplayed'.", [ + $this->logger->notice("MemoryMapper: '{backend}' marked '{title}' as 'unplayed'.", [ 'id' => $cloned->id, 'backend' => $entity->via, 'title' => $cloned->getName(), @@ -324,7 +324,7 @@ private function handleOldEntity(string|int $pointer, iState $cloned, iState $en $this->objects[$pointer] = $this->objects[$pointer]->apply(entity: $entity, fields: $_keys); $this->logger->notice( - $progress ? "MAPPER: '{backend}' updated '{title}' due to play progress change." : "MAPPER: '{backend}' updated '{title}' metadata.", + $progress ? "MemoryMapper: '{backend}' updated '{title}' due to play progress change." : "MemoryMapper: '{backend}' updated '{title}' metadata.", [ 'id' => $cloned->id, 'backend' => $entity->via, @@ -354,7 +354,7 @@ private function handleOldEntity(string|int $pointer, iState $cloned, iState $en if ($entity->isWatched() !== $this->objects[$pointer]->isWatched()) { $this->logger->notice( - "MAPPER: '{backend}' item '{id}: {title}' is marked as '{state}' vs local state '{local_state}', However due to the remote item date '{remote_date}' being older than the last backend sync date '{local_date}'. it was not considered as valid state.", + "MemoryMapper: '{backend}' item '{id}: {title}' is marked as '{state}' vs local state '{local_state}', However due to the remote item date '{remote_date}' being older than the last backend sync date '{local_date}'. it was not considered as valid state.", [ 'id' => $this->objects[$pointer]->id, 'backend' => $entity->via, @@ -369,7 +369,7 @@ private function handleOldEntity(string|int $pointer, iState $cloned, iState $en } if ($this->inTraceMode()) { - $this->logger->debug("MAPPER: Ignoring '{backend}' '{title}'. No changes detected.", [ + $this->logger->debug("MemoryMapper: Ignoring '{backend}' '{title}'. No changes detected.", [ 'id' => $cloned->id, 'backend' => $entity->via, 'title' => $cloned->getName(), @@ -385,7 +385,7 @@ private function handleOldEntity(string|int $pointer, iState $cloned, iState $en public function add(iState $entity, array $opts = []): self { if (false === $entity->hasGuids() && false === $entity->hasRelativeGuid()) { - $this->logger->warning("MAPPER: Ignoring '{backend}' '{title}'. No valid/supported external ids.", [ + $this->logger->warning("MemoryMapper: Ignoring '{backend}' '{title}'. No valid/supported external ids.", [ 'id' => $entity->id, 'backend' => $entity->via, 'title' => $entity->getName(), @@ -396,7 +396,7 @@ public function add(iState $entity, array $opts = []): self if (true === $entity->isEpisode() && $entity->episode < 1) { $this->logger->warning( - "MAPPER: Ignoring '{backend}' '{id}: {title}'. Item was marked as episode but no episode number was provided.", + "MemoryMapper: Ignoring '{backend}' '{id}: {title}'. Item was marked as episode but no episode number was provided.", [ 'id' => $entity->id ?? ag($entity->getMetadata($entity->via), iState::COLUMN_ID, ''), 'backend' => $entity->via, @@ -444,7 +444,7 @@ public function add(iState $entity, array $opts = []): self * 3 - mark entity as tainted and re-process it. */ if (true === $hasAfter && true === $cloned->isWatched() && false === $entity->isWatched()) { - $message = "MAPPER: Watch state conflict detected in '{backend}: {title}' '{new_state}' vs local state '{id}: {current_state}'."; + $message = "MemoryMapper: Watch state conflict detected in '{backend}: {title}' '{new_state}' vs local state '{id}: {current_state}'."; $hasMeta = count($cloned->getMetadata($entity->via)) >= 1; $hasDate = $entity->updated === ag($cloned->getMetadata($entity->via), iState::COLUMN_META_DATA_PLAYED_AT); @@ -492,10 +492,10 @@ public function add(iState $entity, array $opts = []): self $changes = $this->objects[$pointer]->diff(fields: $keys); - $message = "MAPPER: '{backend}' Updated '{title}'."; + $message = "MemoryMapper: '{backend}' Updated '{title}'."; if ($cloned->isWatched() !== $this->objects[$pointer]->isWatched()) { - $message = "MAPPER: '{backend}' Updated and marked '{id}: {title}' as '{state}'."; + $message = "MemoryMapper: '{backend}' Updated and marked '{id}: {title}' as '{state}'."; } if (count($changes) >= 1) { @@ -525,7 +525,10 @@ public function add(iState $entity, array $opts = []): self ]; } - $this->logger->debug("MAPPER: Ignoring '{backend}' '{title}'. Metadata & play state are identical.", $context); + $this->logger->debug( + "MemoryMapper: Ignoring '{backend}' '{title}'. Metadata & play state are identical.", + $context + ); Message::increment("{$entity->via}.{$entity->type}.ignored_no_change"); @@ -597,13 +600,13 @@ public function commit(): mixed $count = count($this->changed); if (0 === $count) { - $this->logger->notice('MAPPER: No changes detected.'); + $this->logger->notice('MemoryMapper: No changes detected.'); return $list; } $inDryRunMode = $this->inDryRunMode(); if (true === $inDryRunMode) { - $this->logger->notice("MAPPER: Recorded '{total}' object changes.", ['total' => $count]); + $this->logger->notice("MemoryMapper: Recorded '{total}' object changes.", ['total' => $count]); } foreach ($this->changed as $pointer) { diff --git a/src/Libs/Mappers/Import/NullMapper.php b/src/Libs/Mappers/Import/NullMapper.php new file mode 100644 index 00000000..76a92da6 --- /dev/null +++ b/src/Libs/Mappers/Import/NullMapper.php @@ -0,0 +1,105 @@ +fullyLoaded = true; + parent::__construct($logger, $db, $cache); + } + + public function loadData(?iDate $date = null): static + { + $this->fullyLoaded = true; + return $this; + } + + public function add(iState $entity, array $opts = []): static + { + $this->fullyLoaded = true; + return parent::add($entity, $opts); + } + + /** + * @inheritdoc + */ + public function remove(iState $entity): bool + { + if (false === ($pointer = $this->getPointer($entity))) { + return false; + } + + $this->removePointers($this->objects[$pointer]); + + if (null !== ($this->objects[$pointer] ?? null)) { + unset($this->objects[$pointer]); + } + + if (null !== ($this->changed[$pointer] ?? null)) { + unset($this->changed[$pointer]); + } + + return true; + } + + /** + * @inheritdoc + */ + public function commit(): array + { + $this->reset(); + + return [ + iState::TYPE_MOVIE => ['added' => 0, 'updated' => 0, 'failed' => 0], + iState::TYPE_EPISODE => ['added' => 0, 'updated' => 0, 'failed' => 0], + ]; + } + + /** + * Compute the play state for each backend. + * + * @param array $backends List of backends to check. + * + * @return array List of changes for each backend. + */ + public function computeChanges(array $backends): array + { + $changes = []; + + foreach ($backends as $backend) { + $changes[$backend] = []; + } + + foreach ($this->objects as $entity) { + $state = $entity->isSynced($backends); + foreach ($state as $b => $value) { + if (false === $value) { + $changes[$b][] = $entity; + } + } + } + + return $changes; + } + + public function __destruct() + { + // -- disabled autocommit. + } +} From 211ef168f4034a06ef4d7540dcf2c49960b157b0 Mon Sep 17 00:00:00 2001 From: ArabCoders Date: Sat, 18 Jan 2025 02:05:20 +0300 Subject: [PATCH 5/6] updated dependencies. --- composer.lock | 105 +++-- frontend/yarn.lock | 916 ++++++++++++++++++++------------------ src/API/Backend/Stale.php | 77 +++- 3 files changed, 612 insertions(+), 486 deletions(-) diff --git a/composer.lock b/composer.lock index 8810a128..ec45dad9 100644 --- a/composer.lock +++ b/composer.lock @@ -581,16 +581,16 @@ }, { "name": "nikic/php-parser", - "version": "v5.3.1", + "version": "v5.4.0", "source": { "type": "git", "url": "https://github.com/nikic/PHP-Parser.git", - "reference": "8eea230464783aa9671db8eea6f8c6ac5285794b" + "reference": "447a020a1f875a434d62f2a401f53b82a396e494" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/8eea230464783aa9671db8eea6f8c6ac5285794b", - "reference": "8eea230464783aa9671db8eea6f8c6ac5285794b", + "url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/447a020a1f875a434d62f2a401f53b82a396e494", + "reference": "447a020a1f875a434d62f2a401f53b82a396e494", "shasum": "" }, "require": { @@ -633,9 +633,9 @@ ], "support": { "issues": "https://github.com/nikic/PHP-Parser/issues", - "source": "https://github.com/nikic/PHP-Parser/tree/v5.3.1" + "source": "https://github.com/nikic/PHP-Parser/tree/v5.4.0" }, - "time": "2024-10-08T18:51:32+00:00" + "time": "2024-12-30T11:07:19+00:00" }, { "name": "nyholm/psr7", @@ -2059,16 +2059,16 @@ }, { "name": "symfony/http-client", - "version": "v7.2.1", + "version": "v7.2.2", "source": { "type": "git", "url": "https://github.com/symfony/http-client.git", - "reference": "ff4df2b68d1c67abb9fef146e6540ea16b58d99e" + "reference": "339ba21476eb184290361542f732ad12c97591ec" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/http-client/zipball/ff4df2b68d1c67abb9fef146e6540ea16b58d99e", - "reference": "ff4df2b68d1c67abb9fef146e6540ea16b58d99e", + "url": "https://api.github.com/repos/symfony/http-client/zipball/339ba21476eb184290361542f732ad12c97591ec", + "reference": "339ba21476eb184290361542f732ad12c97591ec", "shasum": "" }, "require": { @@ -2134,7 +2134,7 @@ "http" ], "support": { - "source": "https://github.com/symfony/http-client/tree/v7.2.1" + "source": "https://github.com/symfony/http-client/tree/v7.2.2" }, "funding": [ { @@ -2150,7 +2150,7 @@ "type": "tidelift" } ], - "time": "2024-12-07T08:50:44+00:00" + "time": "2024-12-30T18:35:15+00:00" }, { "name": "symfony/http-client-contracts", @@ -3072,16 +3072,16 @@ }, { "name": "phpstan/phpstan", - "version": "2.0.4", + "version": "2.1.1", "source": { "type": "git", "url": "https://github.com/phpstan/phpstan.git", - "reference": "50d276fc3bf1430ec315f2f109bbde2769821524" + "reference": "cd6e973e04b4c2b94c86e8612b5a65f0da0e08e7" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpstan/phpstan/zipball/50d276fc3bf1430ec315f2f109bbde2769821524", - "reference": "50d276fc3bf1430ec315f2f109bbde2769821524", + "url": "https://api.github.com/repos/phpstan/phpstan/zipball/cd6e973e04b4c2b94c86e8612b5a65f0da0e08e7", + "reference": "cd6e973e04b4c2b94c86e8612b5a65f0da0e08e7", "shasum": "" }, "require": { @@ -3126,7 +3126,7 @@ "type": "github" } ], - "time": "2024-12-17T17:14:01+00:00" + "time": "2025-01-05T16:43:48+00:00" }, { "name": "phpunit/php-code-coverage", @@ -3453,16 +3453,16 @@ }, { "name": "phpunit/phpunit", - "version": "11.5.2", + "version": "11.5.3", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/phpunit.git", - "reference": "153d0531b9f7e883c5053160cad6dd5ac28140b3" + "reference": "30e319e578a7b5da3543073e30002bf82042f701" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/153d0531b9f7e883c5053160cad6dd5ac28140b3", - "reference": "153d0531b9f7e883c5053160cad6dd5ac28140b3", + "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/30e319e578a7b5da3543073e30002bf82042f701", + "reference": "30e319e578a7b5da3543073e30002bf82042f701", "shasum": "" }, "require": { @@ -3483,7 +3483,7 @@ "phpunit/php-timer": "^7.0.1", "sebastian/cli-parser": "^3.0.2", "sebastian/code-unit": "^3.0.2", - "sebastian/comparator": "^6.2.1", + "sebastian/comparator": "^6.3.0", "sebastian/diff": "^6.0.2", "sebastian/environment": "^7.2.0", "sebastian/exporter": "^6.3.0", @@ -3534,7 +3534,7 @@ "support": { "issues": "https://github.com/sebastianbergmann/phpunit/issues", "security": "https://github.com/sebastianbergmann/phpunit/security/policy", - "source": "https://github.com/sebastianbergmann/phpunit/tree/11.5.2" + "source": "https://github.com/sebastianbergmann/phpunit/tree/11.5.3" }, "funding": [ { @@ -3550,7 +3550,7 @@ "type": "tidelift" } ], - "time": "2024-12-21T05:51:08+00:00" + "time": "2025-01-13T09:36:00+00:00" }, { "name": "psalm/phar", @@ -3593,12 +3593,12 @@ "source": { "type": "git", "url": "https://github.com/Roave/SecurityAdvisories.git", - "reference": "9dd07280fc4c5f6c3d2a3da5e4058fc7288c2a1d" + "reference": "e7a38fcc13e4ddfe9a28d5c7bf50aa9a9da758ec" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/Roave/SecurityAdvisories/zipball/9dd07280fc4c5f6c3d2a3da5e4058fc7288c2a1d", - "reference": "9dd07280fc4c5f6c3d2a3da5e4058fc7288c2a1d", + "url": "https://api.github.com/repos/Roave/SecurityAdvisories/zipball/e7a38fcc13e4ddfe9a28d5c7bf50aa9a9da758ec", + "reference": "e7a38fcc13e4ddfe9a28d5c7bf50aa9a9da758ec", "shasum": "" }, "conflict": { @@ -3720,7 +3720,7 @@ "datatables/datatables": "<1.10.10", "david-garcia/phpwhois": "<=4.3.1", "dbrisinajumi/d2files": "<1", - "dcat/laravel-admin": "<=2.1.3", + "dcat/laravel-admin": "<=2.1.3|==2.2.0.0-beta|==2.2.2.0-beta", "derhansen/fe_change_pwd": "<2.0.5|>=3,<3.0.3", "derhansen/sf_event_mgt": "<4.3.1|>=5,<5.1.1|>=7,<7.4", "desperado/xml-bundle": "<=0.1.7", @@ -3834,6 +3834,7 @@ "gilacms/gila": "<=1.15.4", "gleez/cms": "<=1.3|==2", "globalpayments/php-sdk": "<2", + "goalgorilla/open_social": "<12.3.8|>=12.4,<12.4.5|>=13.0.0.0-alpha1,<13.0.0.0-alpha11", "gogentooss/samlbase": "<1.2.7", "google/protobuf": "<3.15", "gos/web-socket-bundle": "<1.10.4|>=2,<2.6.1|>=3,<3.3", @@ -3842,6 +3843,7 @@ "grumpydictator/firefly-iii": "<6.1.17", "gugoan/economizzer": "<=0.9.0.0-beta1", "guzzlehttp/guzzle": "<6.5.8|>=7,<7.4.5", + "guzzlehttp/oauth-subscriber": "<0.8.1", "guzzlehttp/psr7": "<1.9.1|>=2,<2.4.5", "haffner/jh_captcha": "<=2.1.3|>=3,<=3.0.2", "harvesthq/chosen": "<1.8.7", @@ -3880,6 +3882,7 @@ "intelliants/subrion": "<4.2.2", "inter-mediator/inter-mediator": "==5.5", "ipl/web": "<0.10.1", + "islandora/crayfish": "<4.1", "islandora/islandora": ">=2,<2.4.1", "ivankristianto/phpwhois": "<=4.3", "jackalope/jackalope-doctrine-dbal": "<1.7.4", @@ -3962,6 +3965,7 @@ "mediawiki/abuse-filter": "<1.39.9|>=1.40,<1.41.3|>=1.42,<1.42.2", "mediawiki/cargo": "<3.6.1", "mediawiki/core": "<1.39.5|==1.40", + "mediawiki/data-transfer": ">=1.39,<1.39.11|>=1.41,<1.41.3|>=1.42,<1.42.2", "mediawiki/matomo": "<2.4.3", "mediawiki/semantic-media-wiki": "<4.0.2", "melisplatform/melis-asset-manager": "<5.0.1", @@ -4002,10 +4006,12 @@ "neos/media-browser": "<7.3.19|>=8,<8.0.16|>=8.1,<8.1.11|>=8.2,<8.2.11|>=8.3,<8.3.9", "neos/neos": ">=1.1,<1.1.3|>=1.2,<1.2.13|>=2,<2.0.4|>=2.3,<3.0.20|>=3.1,<3.1.18|>=3.2,<3.2.14|>=3.3,<5.3.10|>=7,<7.0.9|>=7.1,<7.1.7|>=7.2,<7.2.6|>=7.3,<7.3.4|>=8,<8.0.2", "neos/swiftmailer": "<5.4.5", + "nesbot/carbon": "<2.72.6|>=3,<3.8.4", + "netcarver/textile": "<=4.1.2", "netgen/tagsbundle": ">=3.4,<3.4.11|>=4,<4.0.15", "nette/application": ">=2,<2.0.19|>=2.1,<2.1.13|>=2.2,<2.2.10|>=2.3,<2.3.14|>=2.4,<2.4.16|>=3,<3.0.6", "nette/nette": ">=2,<2.0.19|>=2.1,<2.1.13", - "nilsteampassnet/teampass": "<3.0.10", + "nilsteampassnet/teampass": "<3.1.3.1-dev", "nonfiction/nterchange": "<4.1.1", "notrinos/notrinos-erp": "<=0.7", "noumo/easyii": "<=0.9", @@ -4066,10 +4072,10 @@ "phpmailer/phpmailer": "<6.5", "phpmussel/phpmussel": ">=1,<1.6", "phpmyadmin/phpmyadmin": "<5.2.1", - "phpmyfaq/phpmyfaq": "<3.2.5|==3.2.5", + "phpmyfaq/phpmyfaq": "<3.2.5|==3.2.5|>=3.2.10,<=4.0.1", "phpoffice/common": "<0.2.9", "phpoffice/phpexcel": "<1.8.1", - "phpoffice/phpspreadsheet": "<1.29.4|>=2,<2.1.3|>=2.2,<2.3.2|>=3.3,<3.4", + "phpoffice/phpspreadsheet": "<=1.29.6|>=2,<=2.1.5|>=2.2,<=2.3.4|>=3,<3.7", "phpseclib/phpseclib": "<2.0.47|>=3,<3.0.36", "phpservermon/phpservermon": "<3.6", "phpsysinfo/phpsysinfo": "<3.4.3", @@ -4155,7 +4161,7 @@ "silverstripe/cms": "<4.11.3", "silverstripe/comments": ">=1.3,<3.1.1", "silverstripe/forum": "<=0.6.1|>=0.7,<=0.7.3", - "silverstripe/framework": "<5.2.16", + "silverstripe/framework": "<5.3.8", "silverstripe/graphql": ">=2,<2.0.5|>=3,<3.8.2|>=4,<4.3.7|>=5,<5.1.3", "silverstripe/hybridsessions": ">=1,<2.4.1|>=2.5,<2.5.1", "silverstripe/recipe-cms": ">=4.5,<4.5.3", @@ -4195,6 +4201,7 @@ "squizlabs/php_codesniffer": ">=1,<2.8.1|>=3,<3.0.1", "ssddanbrown/bookstack": "<24.05.1", "starcitizentools/citizen-skin": ">=2.6.3,<2.31", + "starcitizentools/tabber-neue": ">=1.9.1,<2.7.2", "statamic/cms": "<=5.16", "stormpath/sdk": "<9.9.99", "studio-42/elfinder": "<=2.1.64", @@ -4266,7 +4273,7 @@ "thelia/thelia": ">=2.1,<2.1.3", "theonedemon/phpwhois": "<=4.2.5", "thinkcmf/thinkcmf": "<6.0.8", - "thorsten/phpmyfaq": "<4", + "thorsten/phpmyfaq": "<=4.0.1", "tikiwiki/tiki-manager": "<=17.1", "timber/timber": ">=0.16.6,<1.23.1|>=1.24,<1.24.1|>=2,<2.1", "tinymce/tinymce": "<7.2", @@ -4286,13 +4293,20 @@ "twig/twig": "<3.11.2|>=3.12,<3.14.1", "typo3/cms": "<9.5.29|>=10,<10.4.35|>=11,<11.5.23|>=12,<12.2", "typo3/cms-backend": "<4.1.14|>=4.2,<4.2.15|>=4.3,<4.3.7|>=4.4,<4.4.4|>=7,<=7.6.50|>=8,<=8.7.39|>=9,<=9.5.24|>=10,<10.4.46|>=11,<11.5.40|>=12,<12.4.21|>=13,<13.3.1", - "typo3/cms-core": "<=8.7.56|>=9,<=9.5.47|>=10,<=10.4.44|>=11,<=11.5.36|>=12,<=12.4.14|>=13,<=13.1", + "typo3/cms-belog": ">=10,<=10.4.47|>=11,<=11.5.41|>=12,<=12.4.24|>=13,<=13.4.2", + "typo3/cms-beuser": ">=10,<=10.4.47|>=11,<=11.5.41|>=12,<=12.4.24|>=13,<=13.4.2", + "typo3/cms-core": "<=8.7.56|>=9,<=9.5.48|>=10,<=10.4.47|>=11,<=11.5.41|>=12,<=12.4.24|>=13,<=13.4.2", + "typo3/cms-dashboard": ">=10,<=10.4.47|>=11,<=11.5.41|>=12,<=12.4.24|>=13,<=13.4.2", "typo3/cms-extbase": "<6.2.24|>=7,<7.6.8|==8.1.1", + "typo3/cms-extensionmanager": ">=10,<=10.4.47|>=11,<=11.5.41|>=12,<=12.4.24|>=13,<=13.4.2", "typo3/cms-fluid": "<4.3.4|>=4.4,<4.4.1", - "typo3/cms-form": ">=8,<=8.7.39|>=9,<=9.5.24|>=10,<=10.4.13|>=11,<=11.1", + "typo3/cms-form": ">=8,<=8.7.39|>=9,<=9.5.24|>=10,<=10.4.47|>=11,<=11.5.41|>=12,<=12.4.24|>=13,<=13.4.2", "typo3/cms-frontend": "<4.3.9|>=4.4,<4.4.5", - "typo3/cms-install": "<4.1.14|>=4.2,<4.2.16|>=4.3,<4.3.9|>=4.4,<4.4.5|>=12.2,<12.4.8", + "typo3/cms-indexed-search": ">=10,<=10.4.47|>=11,<=11.5.41|>=12,<=12.4.24|>=13,<=13.4.2", + "typo3/cms-install": "<4.1.14|>=4.2,<4.2.16|>=4.3,<4.3.9|>=4.4,<4.4.5|>=12.2,<12.4.8|==13.4.2", + "typo3/cms-lowlevel": ">=11,<=11.5.41", "typo3/cms-rte-ckeditor": ">=9.5,<9.5.42|>=10,<10.4.39|>=11,<11.5.30", + "typo3/cms-scheduler": ">=11,<=11.5.41", "typo3/flow": ">=1,<1.0.4|>=1.1,<1.1.1|>=2,<2.0.1|>=2.3,<2.3.16|>=3,<3.0.12|>=3.1,<3.1.10|>=3.2,<3.2.13|>=3.3,<3.3.13|>=4,<4.0.6", "typo3/html-sanitizer": ">=1,<=1.5.2|>=2,<=2.1.3", "typo3/neos": ">=1.1,<1.1.3|>=1.2,<1.2.13|>=2,<2.0.4|>=2.3,<2.3.99|>=3,<3.0.20|>=3.1,<3.1.18|>=3.2,<3.2.14|>=3.3,<3.3.23|>=4,<4.0.17|>=4.1,<4.1.16|>=4.2,<4.2.12|>=4.3,<4.3.3", @@ -4350,7 +4364,7 @@ "xpressengine/xpressengine": "<3.0.15", "yab/quarx": "<2.4.5", "yeswiki/yeswiki": "<=4.4.4", - "yetiforce/yetiforce-crm": "<=6.4", + "yetiforce/yetiforce-crm": "<6.5", "yidashi/yii2cmf": "<=2", "yii2mod/yii2-cms": "<1.9.2", "yiisoft/yii": "<1.1.29", @@ -4440,7 +4454,7 @@ "type": "tidelift" } ], - "time": "2024-12-27T20:05:23+00:00" + "time": "2025-01-15T23:05:13+00:00" }, { "name": "sebastian/cli-parser", @@ -4614,16 +4628,16 @@ }, { "name": "sebastian/comparator", - "version": "6.2.1", + "version": "6.3.0", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/comparator.git", - "reference": "43d129d6a0f81c78bee378b46688293eb7ea3739" + "reference": "d4e47a769525c4dd38cea90e5dcd435ddbbc7115" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/comparator/zipball/43d129d6a0f81c78bee378b46688293eb7ea3739", - "reference": "43d129d6a0f81c78bee378b46688293eb7ea3739", + "url": "https://api.github.com/repos/sebastianbergmann/comparator/zipball/d4e47a769525c4dd38cea90e5dcd435ddbbc7115", + "reference": "d4e47a769525c4dd38cea90e5dcd435ddbbc7115", "shasum": "" }, "require": { @@ -4636,6 +4650,9 @@ "require-dev": { "phpunit/phpunit": "^11.4" }, + "suggest": { + "ext-bcmath": "For comparing BcMath\\Number objects" + }, "type": "library", "extra": { "branch-alias": { @@ -4679,7 +4696,7 @@ "support": { "issues": "https://github.com/sebastianbergmann/comparator/issues", "security": "https://github.com/sebastianbergmann/comparator/security/policy", - "source": "https://github.com/sebastianbergmann/comparator/tree/6.2.1" + "source": "https://github.com/sebastianbergmann/comparator/tree/6.3.0" }, "funding": [ { @@ -4687,7 +4704,7 @@ "type": "github" } ], - "time": "2024-10-31T05:30:08+00:00" + "time": "2025-01-06T10:28:19+00:00" }, { "name": "sebastian/complexity", diff --git a/frontend/yarn.lock b/frontend/yarn.lock index fe2bbeaf..a5658bf0 100644 --- a/frontend/yarn.lock +++ b/frontend/yarn.lock @@ -24,10 +24,10 @@ js-tokens "^4.0.0" picocolors "^1.0.0" -"@babel/compat-data@^7.25.9": - version "7.26.3" - resolved "https://registry.yarnpkg.com/@babel/compat-data/-/compat-data-7.26.3.tgz#99488264a56b2aded63983abd6a417f03b92ed02" - integrity sha512-nHIxvKPniQXpmQLb0vhY3VaFb3S0YrTAwpOWJZh1wn3oJPjJk9Asva204PsBdmAE8vpzfHudT8DB0scYvy9q0g== +"@babel/compat-data@^7.26.5": + version "7.26.5" + resolved "https://registry.yarnpkg.com/@babel/compat-data/-/compat-data-7.26.5.tgz#df93ac37f4417854130e21d72c66ff3d4b897fc7" + integrity sha512-XvcZi1KWf88RVbF9wn8MN6tYFloU5qX8KjuF3E1PVBmJ9eypXfs4GRiJwLuTZL0iSnJUKn1BFPa5BPZZJyFzPg== "@babel/core@^7.23.0", "@babel/core@^7.26.0": version "7.26.0" @@ -50,13 +50,13 @@ json5 "^2.2.3" semver "^6.3.1" -"@babel/generator@^7.26.0", "@babel/generator@^7.26.3": - version "7.26.3" - resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.26.3.tgz#ab8d4360544a425c90c248df7059881f4b2ce019" - integrity sha512-6FF/urZvD0sTeO7k6/B15pMLC4CHUv1426lzr3N01aHJTl046uCAh9LXW/fzeXXjPNCJ6iABW5XaWOsIZB93aQ== +"@babel/generator@^7.26.0", "@babel/generator@^7.26.5": + version "7.26.5" + resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.26.5.tgz#e44d4ab3176bbcaf78a5725da5f1dc28802a9458" + integrity sha512-2caSP6fN9I7HOe6nqhtft7V4g7/V/gfDsC3Ag4W7kEzzvRGKqiv0pu0HogPiZ3KaVSoNDhUws6IJjDjpfmYIXw== dependencies: - "@babel/parser" "^7.26.3" - "@babel/types" "^7.26.3" + "@babel/parser" "^7.26.5" + "@babel/types" "^7.26.5" "@jridgewell/gen-mapping" "^0.3.5" "@jridgewell/trace-mapping" "^0.3.25" jsesc "^3.0.2" @@ -69,11 +69,11 @@ "@babel/types" "^7.25.9" "@babel/helper-compilation-targets@^7.25.9": - version "7.25.9" - resolved "https://registry.yarnpkg.com/@babel/helper-compilation-targets/-/helper-compilation-targets-7.25.9.tgz#55af025ce365be3cdc0c1c1e56c6af617ce88875" - integrity sha512-j9Db8Suy6yV/VHa4qzrj9yZfZxhLWQdVnRlXxmKLYlhWUVB1sB2G5sxuWYXk/whHD9iW76PmNzxZ4UCnTQTVEQ== + version "7.26.5" + resolved "https://registry.yarnpkg.com/@babel/helper-compilation-targets/-/helper-compilation-targets-7.26.5.tgz#75d92bb8d8d51301c0d49e52a65c9a7fe94514d8" + integrity sha512-IXuyn5EkouFJscIDuFF5EsiSolseme1s0CZB+QxVugqJLYmKdxI1VfIBOst0SUu4rnk2Z7kqTwmoO1lp3HIfnA== dependencies: - "@babel/compat-data" "^7.25.9" + "@babel/compat-data" "^7.26.5" "@babel/helper-validator-option" "^7.25.9" browserslist "^4.24.0" lru-cache "^5.1.1" @@ -124,19 +124,19 @@ dependencies: "@babel/types" "^7.25.9" -"@babel/helper-plugin-utils@^7.10.4", "@babel/helper-plugin-utils@^7.24.8", "@babel/helper-plugin-utils@^7.25.9": - version "7.25.9" - resolved "https://registry.yarnpkg.com/@babel/helper-plugin-utils/-/helper-plugin-utils-7.25.9.tgz#9cbdd63a9443a2c92a725cca7ebca12cc8dd9f46" - integrity sha512-kSMlyUVdWe25rEsRGviIgOWnoT/nfABVWlqt9N19/dIPWViAOW2s9wznP5tURbs/IDuNk4gPy3YdYRgH3uxhBw== +"@babel/helper-plugin-utils@^7.10.4", "@babel/helper-plugin-utils@^7.24.8", "@babel/helper-plugin-utils@^7.25.9", "@babel/helper-plugin-utils@^7.26.5": + version "7.26.5" + resolved "https://registry.yarnpkg.com/@babel/helper-plugin-utils/-/helper-plugin-utils-7.26.5.tgz#18580d00c9934117ad719392c4f6585c9333cc35" + integrity sha512-RS+jZcRdZdRFzMyr+wcsaqOmld1/EqTghfaBGQQd/WnRdzdlvSZ//kF7U8VQTxf1ynZ4cjUcYgjVGx13ewNPMg== "@babel/helper-replace-supers@^7.25.9": - version "7.25.9" - resolved "https://registry.yarnpkg.com/@babel/helper-replace-supers/-/helper-replace-supers-7.25.9.tgz#ba447224798c3da3f8713fc272b145e33da6a5c5" - integrity sha512-IiDqTOTBQy0sWyeXyGSC5TBJpGFXBkRynjBeXsvbhQFKj2viwJC76Epz35YLU1fpe/Am6Vppb7W7zM4fPQzLsQ== + version "7.26.5" + resolved "https://registry.yarnpkg.com/@babel/helper-replace-supers/-/helper-replace-supers-7.26.5.tgz#6cb04e82ae291dae8e72335dfe438b0725f14c8d" + integrity sha512-bJ6iIVdYX1YooY2X7w1q6VITt+LnUILtNk7zT78ykuwStx8BauCzxvFqFaHjOpW1bVnSUM1PN1f0p5P21wHxvg== dependencies: "@babel/helper-member-expression-to-functions" "^7.25.9" "@babel/helper-optimise-call-expression" "^7.25.9" - "@babel/traverse" "^7.25.9" + "@babel/traverse" "^7.26.5" "@babel/helper-skip-transparent-expression-wrappers@^7.25.9": version "7.25.9" @@ -169,12 +169,12 @@ "@babel/template" "^7.25.9" "@babel/types" "^7.26.0" -"@babel/parser@^7.25.3", "@babel/parser@^7.25.4", "@babel/parser@^7.25.6", "@babel/parser@^7.25.9", "@babel/parser@^7.26.0", "@babel/parser@^7.26.2", "@babel/parser@^7.26.3": - version "7.26.3" - resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.26.3.tgz#8c51c5db6ddf08134af1ddbacf16aaab48bac234" - integrity sha512-WJ/CvmY8Mea8iDXo6a7RK2wbmJITT5fN3BEkRuFlxVyNx8jOKIIhmC4fSkTcPcf8JyavbBwIe6OpiCOBXt/IcA== +"@babel/parser@^7.25.3", "@babel/parser@^7.25.4", "@babel/parser@^7.25.6", "@babel/parser@^7.25.9", "@babel/parser@^7.26.0", "@babel/parser@^7.26.2", "@babel/parser@^7.26.5": + version "7.26.5" + resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.26.5.tgz#6fec9aebddef25ca57a935c86dbb915ae2da3e1f" + integrity sha512-SRJ4jYmXRqV1/Xc+TIVG84WjHBXKlxO9sHQnA2Pf12QQEAp1LOh6kDzNHXcUnbH1QI0FDoPPVOt+vyUDucxpaw== dependencies: - "@babel/types" "^7.26.3" + "@babel/types" "^7.26.5" "@babel/plugin-proposal-decorators@^7.23.0": version "7.25.9" @@ -221,20 +221,20 @@ "@babel/helper-plugin-utils" "^7.25.9" "@babel/plugin-transform-typescript@^7.22.15", "@babel/plugin-transform-typescript@^7.25.9": - version "7.26.3" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-typescript/-/plugin-transform-typescript-7.26.3.tgz#3d6add9c78735623317387ee26d5ada540eee3fd" - integrity sha512-6+5hpdr6mETwSKjmJUdYw0EIkATiQhnELWlE3kJFBwSg/BGIVwVaVbX+gOXBCdc7Ln1RXZxyWGecIXhUfnl7oA== + version "7.26.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-typescript/-/plugin-transform-typescript-7.26.5.tgz#6d9b48e8ee40a45a3ed12ebc013449fdf261714c" + integrity sha512-GJhPO0y8SD5EYVCy2Zr+9dSZcEgaSmq5BLR0Oc25TOEhC+ba49vUAGZFjy8v79z9E1mdldq4x9d1xgh4L1d5dQ== dependencies: "@babel/helper-annotate-as-pure" "^7.25.9" "@babel/helper-create-class-features-plugin" "^7.25.9" - "@babel/helper-plugin-utils" "^7.25.9" + "@babel/helper-plugin-utils" "^7.26.5" "@babel/helper-skip-transparent-expression-wrappers" "^7.25.9" "@babel/plugin-syntax-typescript" "^7.25.9" "@babel/standalone@^7.26.4": - version "7.26.4" - resolved "https://registry.yarnpkg.com/@babel/standalone/-/standalone-7.26.4.tgz#440d8046929174b463e2c6294fc8f6d49fdea550" - integrity sha512-SF+g7S2mhTT1b7CHyfNjDkPU1corxg4LPYsyP0x5KuCl+EbtBQHRLqr9N3q7e7+x7NQ5LYxQf8mJ2PmzebLr0A== + version "7.26.6" + resolved "https://registry.yarnpkg.com/@babel/standalone/-/standalone-7.26.6.tgz#d1af5d3fe0b635d4571e5a42d1018b3291bd58a6" + integrity sha512-h1mkoNFYCqDkS+vTLGzsQYvp1v1qbuugk4lOtb/oyjArZ+EtreAaxcSYg3rSIzWZRQOjx4iqGe7A8NRYIMSTTw== "@babel/template@^7.25.0", "@babel/template@^7.25.9": version "7.25.9" @@ -245,23 +245,23 @@ "@babel/parser" "^7.25.9" "@babel/types" "^7.25.9" -"@babel/traverse@^7.25.6", "@babel/traverse@^7.25.9": - version "7.26.4" - resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.26.4.tgz#ac3a2a84b908dde6d463c3bfa2c5fdc1653574bd" - integrity sha512-fH+b7Y4p3yqvApJALCPJcwb0/XaOSgtK4pzV6WVjPR5GLFQBRI7pfoX2V2iM48NXvX07NUxxm1Vw98YjqTcU5w== +"@babel/traverse@^7.25.6", "@babel/traverse@^7.25.9", "@babel/traverse@^7.26.5": + version "7.26.5" + resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.26.5.tgz#6d0be3e772ff786456c1a37538208286f6e79021" + integrity sha512-rkOSPOw+AXbgtwUga3U4u8RpoK9FEFWBNAlTpcnkLFjL5CT+oyHNuUUC/xx6XefEJ16r38r8Bc/lfp6rYuHeJQ== dependencies: "@babel/code-frame" "^7.26.2" - "@babel/generator" "^7.26.3" - "@babel/parser" "^7.26.3" + "@babel/generator" "^7.26.5" + "@babel/parser" "^7.26.5" "@babel/template" "^7.25.9" - "@babel/types" "^7.26.3" + "@babel/types" "^7.26.5" debug "^4.3.1" globals "^11.1.0" -"@babel/types@^7.25.4", "@babel/types@^7.25.6", "@babel/types@^7.25.9", "@babel/types@^7.26.0", "@babel/types@^7.26.3": - version "7.26.3" - resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.26.3.tgz#37e79830f04c2b5687acc77db97fbc75fb81f3c0" - integrity sha512-vN5p+1kl59GVKMvTHt55NzzmYVxprfJD+ql7U9NFIfKCBkYE55LYtS+WtPlaYOyzydrKI8Nezd+aZextrd+FMA== +"@babel/types@^7.25.4", "@babel/types@^7.25.6", "@babel/types@^7.25.9", "@babel/types@^7.26.0", "@babel/types@^7.26.3", "@babel/types@^7.26.5": + version "7.26.5" + resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.26.5.tgz#7a1e1c01d28e26d1fe7f8ec9567b3b92b9d07747" + integrity sha512-L6mZmwFDK6Cjh1nRCLXpa6no13ZIioJDz7mdkzHv399pThrTa/k0nUlNaenOeh2kWu/iaOQYElEpKPUswUa9Vg== dependencies: "@babel/helper-string-parser" "^7.25.9" "@babel/helper-validator-identifier" "^7.25.9" @@ -514,11 +514,11 @@ integrity sha512-7VTgWzgMGvup6aSqDPLiW5zHaxYJGTO4OokMjIlrCtf+VpEL+cXKtCvg723iguPYI5oaUNdS+/V7OU2gvXVWEg== "@floating-ui/core@^1.1.0": - version "1.6.8" - resolved "https://registry.yarnpkg.com/@floating-ui/core/-/core-1.6.8.tgz#aa43561be075815879305965020f492cdb43da12" - integrity sha512-7XJ9cPU+yI2QeLS+FCSlqNFZJq8arvswefkZrYI1yQBbftw6FyrZOxYSh+9S7z7TpeWlRt9zJ5IhM1WIL334jA== + version "1.6.9" + resolved "https://registry.yarnpkg.com/@floating-ui/core/-/core-1.6.9.tgz#64d1da251433019dafa091de9b2886ff35ec14e6" + integrity sha512-uMXCuQ3BItDUbAMhIXw7UPXRfAlOAvZzdK9BWpE60MCn+Svt3aLn9jsPTi/WNGlRUu2uI0v5S7JiIUsbsvh3fw== dependencies: - "@floating-ui/utils" "^0.2.8" + "@floating-ui/utils" "^0.2.9" "@floating-ui/dom@~1.1.1": version "1.1.1" @@ -527,10 +527,10 @@ dependencies: "@floating-ui/core" "^1.1.0" -"@floating-ui/utils@^0.2.8": - version "0.2.8" - resolved "https://registry.yarnpkg.com/@floating-ui/utils/-/utils-0.2.8.tgz#21a907684723bbbaa5f0974cf7730bd797eb8e62" - integrity sha512-kym7SodPp8/wloecOpcmSnWJsK7M0E5Wg8UcFA+uO4B9s5d0ywXOEro/8HM9x0rW+TljRzul/14UYz3TleT3ig== +"@floating-ui/utils@^0.2.9": + version "0.2.9" + resolved "https://registry.yarnpkg.com/@floating-ui/utils/-/utils-0.2.9.tgz#50dea3616bc8191fb8e112283b49eaff03e78429" + integrity sha512-MDWhGtE+eHw5JW7lq4qhc5yRLS11ERl1c7Z6Xd0a58DozHES6EnNNwUWbMiG4J9Cgj053Bhk8zvlhFYKVhULwg== "@ioredis/commands@^1.1.1": version "1.2.0" @@ -662,6 +662,35 @@ "@nodelib/fs.scandir" "2.1.5" fastq "^1.6.0" +"@nuxt/cli@^3.20.0": + version "3.20.0" + resolved "https://registry.yarnpkg.com/@nuxt/cli/-/cli-3.20.0.tgz#748165c9670e96a32bd9108a0451d548de13c4cb" + integrity sha512-TmQPjIHXJFPTssPMMFuLF48nr9cm6ctaNwrnhDFl4xLunfLR4rrMJNJAQhepWyukg970ZgokZVbUYMqf6eCnTQ== + dependencies: + c12 "^2.0.1" + chokidar "^4.0.3" + citty "^0.1.6" + clipboardy "^4.0.0" + consola "^3.3.3" + defu "^6.1.4" + fuse.js "^7.0.0" + giget "^1.2.3" + h3 "^1.13.0" + httpxy "^0.1.5" + jiti "^2.4.2" + listhen "^1.9.0" + nypm "^0.4.1" + ofetch "^1.4.1" + ohash "^1.1.4" + pathe "^2.0.1" + perfect-debounce "^1.0.0" + pkg-types "^1.3.0" + scule "^1.3.0" + semver "^7.6.3" + std-env "^3.8.0" + tinyexec "^0.3.2" + ufo "^1.5.4" + "@nuxt/devalue@^2.0.2": version "2.0.2" resolved "https://registry.yarnpkg.com/@nuxt/devalue/-/devalue-2.0.2.tgz#5749f04df13bda4c863338d8dabaf370f45ef7c7" @@ -692,7 +721,7 @@ rc9 "^2.1.2" semver "^7.6.3" -"@nuxt/devtools@^1.6.4": +"@nuxt/devtools@^1.7.0": version "1.7.0" resolved "https://registry.yarnpkg.com/@nuxt/devtools/-/devtools-1.7.0.tgz#988ed20378729caf45636131eedf4471efcabdbc" integrity sha512-uvnjt5Zowkz7tZmnks2cGreg1XZIiSyVzQ2MYiRXACodlXcwJ0dpUS3WTxu8BR562K+772oRdvKie9AQlyZUgg== @@ -735,104 +764,95 @@ which "^3.0.1" ws "^8.18.0" -"@nuxt/kit@3.15.0", "@nuxt/kit@^3.12.1", "@nuxt/kit@^3.14.1592", "@nuxt/kit@^3.15.0": - version "3.15.0" - resolved "https://registry.yarnpkg.com/@nuxt/kit/-/kit-3.15.0.tgz#da52b8acb9e77cd3e6f246a484c4b5743ac0ca6a" - integrity sha512-Q7k11wDTLIbBgoTfRYNrciK7PvjKklewrKd5PRMJCpn9Lmuqkq59HErNfJXFrBKHsE3Ld0DB6WUtpPGOvWJZoQ== +"@nuxt/kit@3.15.2", "@nuxt/kit@^3.12.1", "@nuxt/kit@^3.15.0", "@nuxt/kit@^3.15.1": + version "3.15.2" + resolved "https://registry.yarnpkg.com/@nuxt/kit/-/kit-3.15.2.tgz#edb0b66f08989458329cafac4cbe2960c2d92ebf" + integrity sha512-nxiPJVz2fICcyBKlN5pL1IgZVejyArulREsS5HvAk07hijlYuZ5toRM8soLt51VQNpFd/PedL+Z1AlYu/bQCYQ== dependencies: - "@nuxt/schema" "3.15.0" + "@nuxt/schema" "3.15.2" c12 "^2.0.1" - consola "^3.3.1" + consola "^3.4.0" defu "^6.1.4" destr "^2.0.3" globby "^14.0.2" - ignore "^7.0.0" + ignore "^7.0.3" jiti "^2.4.2" klona "^2.0.6" knitwork "^1.2.0" - mlly "^1.7.3" + mlly "^1.7.4" ohash "^1.1.4" - pathe "^1.1.2" - pkg-types "^1.2.1" + pathe "^2.0.1" + pkg-types "^1.3.1" scule "^1.3.0" semver "^7.6.3" + std-env "^3.8.0" ufo "^1.5.4" unctx "^2.4.1" - unimport "^3.14.5" + unimport "^3.14.6" untyped "^1.5.2" -"@nuxt/schema@3.15.0", "@nuxt/schema@^3.15.0": - version "3.15.0" - resolved "https://registry.yarnpkg.com/@nuxt/schema/-/schema-3.15.0.tgz#d3e6127b02b15cd51bd1f3894e020cffddfd17f3" - integrity sha512-sAgLgSOj/SZxUmlJ/Q3TLRwIAqmiiZ5gCBrT+eq9CowIj7bgxX92pT720pDLEDs4wlXiTTsqC8nyqXQis8pPyA== +"@nuxt/schema@3.15.2", "@nuxt/schema@^3.15.0": + version "3.15.2" + resolved "https://registry.yarnpkg.com/@nuxt/schema/-/schema-3.15.2.tgz#175df2b6893d93b4998f0bccfb0b0b6f151f620b" + integrity sha512-cTHGbLTbrQ83B+7Mh0ggc5MzIp74o8KciA0boCiBJyK5uImH9QQNK6VgfwRWcTD5sj3WNKiIB1luOMom3LHgVw== dependencies: - c12 "^2.0.1" - compatx "^0.1.8" - consola "^3.3.1" + consola "^3.4.0" defu "^6.1.4" - hookable "^5.5.3" - pathe "^1.1.2" - pkg-types "^1.2.1" - scule "^1.3.0" + pathe "^2.0.1" std-env "^3.8.0" - ufo "^1.5.4" - uncrypto "^0.1.3" - unimport "^3.14.5" - untyped "^1.5.2" -"@nuxt/telemetry@^2.6.2": - version "2.6.2" - resolved "https://registry.yarnpkg.com/@nuxt/telemetry/-/telemetry-2.6.2.tgz#83e6ff976389097ff5b506cf1e6ce582f7663944" - integrity sha512-UReyqp35ZFcsyMuP+DmDj/0W/odANCuObdqYyAIR+/Z/9yDHtBO6Cc/wWbjjhrt41yhhco7/+vILELPHWD+wxg== +"@nuxt/telemetry@^2.6.4": + version "2.6.4" + resolved "https://registry.yarnpkg.com/@nuxt/telemetry/-/telemetry-2.6.4.tgz#d35997b02b936fde220f85f0ffc5958f0227a2f7" + integrity sha512-2Lgdn07Suraly5dSfVQ4ttBQBMtmjvCTGKGUHpc1UyH87HT9xCm3KLFO0UcVQ8+LNYCgoOaK7lq9qDJOfBfZ5A== dependencies: - "@nuxt/kit" "^3.14.1592" + "@nuxt/kit" "^3.15.1" citty "^0.1.6" - consola "^3.3.0" + consola "^3.3.1" destr "^2.0.3" dotenv "^16.4.7" git-url-parse "^16.0.0" is-docker "^3.0.0" - jiti "^2.4.2" ofetch "^1.4.1" - package-manager-detector "^0.2.7" + package-manager-detector "^0.2.8" parse-git-config "^3.0.0" - pathe "^1.1.2" + pathe "^2.0.0" rc9 "^2.1.2" std-env "^3.8.0" -"@nuxt/vite-builder@3.15.0": - version "3.15.0" - resolved "https://registry.yarnpkg.com/@nuxt/vite-builder/-/vite-builder-3.15.0.tgz#be94a9666b576226308df60585d6ca233d6fc113" - integrity sha512-cNwX/Q4nqM4hOHbaLUQWdd/cPn8U00GqkTxdxrpzZqTs+A8d8aJQMpuAY+rXclXoU2t0z90HTdSwtgehHGersQ== +"@nuxt/vite-builder@3.15.2": + version "3.15.2" + resolved "https://registry.yarnpkg.com/@nuxt/vite-builder/-/vite-builder-3.15.2.tgz#09837bd33a4c6174bfc50aa101928d99548dda9c" + integrity sha512-YtP6hIOKhqa1JhX0QzuULpA84lseO76bv5OqJzUl7yoaykhOkZjkEk9c20hamtMdoxhVeUAXGZJCsp9Ivjfb3g== dependencies: - "@nuxt/kit" "3.15.0" + "@nuxt/kit" "3.15.2" "@rollup/plugin-replace" "^6.0.2" "@vitejs/plugin-vue" "^5.2.1" "@vitejs/plugin-vue-jsx" "^4.1.1" autoprefixer "^10.4.20" - consola "^3.3.1" + consola "^3.4.0" cssnano "^7.0.6" defu "^6.1.4" esbuild "^0.24.2" escape-string-regexp "^5.0.0" externality "^1.0.2" get-port-please "^3.1.2" - h3 "^1.13.0" + h3 "^1.13.1" jiti "^2.4.2" knitwork "^1.2.0" magic-string "^0.30.17" - mlly "^1.7.3" + mlly "^1.7.4" ohash "^1.1.4" - pathe "^1.1.2" + pathe "^2.0.1" perfect-debounce "^1.0.0" - pkg-types "^1.2.1" - postcss "^8.4.49" - rollup-plugin-visualizer "^5.12.0" + pkg-types "^1.3.1" + postcss "^8.5.1" + rollup-plugin-visualizer "^5.13.1" std-env "^3.8.0" ufo "^1.5.4" unenv "^1.10.0" - unplugin "^2.1.0" - vite "^6.0.5" + unplugin "^2.1.2" + vite "^6.0.7" vite-node "^2.1.8" vite-plugin-checker "^0.8.0" vue-bundle-renderer "^2.1.1" @@ -955,18 +975,18 @@ require-from-string "^2.0.2" uri-js-replace "^1.0.1" -"@redocly/config@^0.17.0": - version "0.17.1" - resolved "https://registry.yarnpkg.com/@redocly/config/-/config-0.17.1.tgz#2def04cecf440dd78c0f102f53f3444fac050768" - integrity sha512-CEmvaJuG7pm2ylQg53emPmtgm4nW2nxBgwXzbVEHpGas/lGnMyN8Zlkgiz6rPw0unASg6VW3wlz27SOL5XFHYQ== +"@redocly/config@^0.20.1": + version "0.20.1" + resolved "https://registry.yarnpkg.com/@redocly/config/-/config-0.20.1.tgz#867e187d8113d0646eab7859c7835ed0656d8315" + integrity sha512-TYiTDtuItiv95YMsrRxyCs1HKLrDPtTvpaD3+kDKXBnFDeJuYKZ+eHXpCr6YeN4inxfVBs7DLhHsQcs9srddyQ== -"@redocly/openapi-core@^1.25.9": - version "1.26.1" - resolved "https://registry.yarnpkg.com/@redocly/openapi-core/-/openapi-core-1.26.1.tgz#d84299f09a3b4f8ca59bafcada7b4d4a040cf26b" - integrity sha512-xRuVZqMVRFzqjbUCpOTra4tbnmQMWsya996omZMV3WgD084Z6OWB3FXflhAp93E/yAmbWlWZpddw758AyoaLSw== +"@redocly/openapi-core@^1.27.0": + version "1.27.2" + resolved "https://registry.yarnpkg.com/@redocly/openapi-core/-/openapi-core-1.27.2.tgz#109163901fd8a2853e805877fe234b65e3c5753a" + integrity sha512-qVrDc27DHpeO2NRCMeRdb4299nijKQE3BY0wrA+WUHlOLScorIi/y7JzammLk22IaTvjR9Mv9aTAdjE1aUwJnA== dependencies: "@redocly/ajv" "^8.11.2" - "@redocly/config" "^0.17.0" + "@redocly/config" "^0.20.1" colorette "^1.2.0" https-proxy-agent "^7.0.4" js-levenshtein "^1.1.6" @@ -1038,7 +1058,7 @@ smob "^1.0.0" terser "^5.17.4" -"@rollup/pluginutils@^5.0.1", "@rollup/pluginutils@^5.1.0", "@rollup/pluginutils@^5.1.2", "@rollup/pluginutils@^5.1.3": +"@rollup/pluginutils@^5.0.1", "@rollup/pluginutils@^5.1.0", "@rollup/pluginutils@^5.1.2", "@rollup/pluginutils@^5.1.3", "@rollup/pluginutils@^5.1.4": version "5.1.4" resolved "https://registry.yarnpkg.com/@rollup/pluginutils/-/pluginutils-5.1.4.tgz#bb94f1f9eaaac944da237767cdfee6c5b2262d4a" integrity sha512-USm05zrsFxYLPdWWq+K3STlWiT/3ELn3RcV5hJMghpeAIhxfsUIg6mt12CBJBInWMV4VneoV7SfGv8xIwo2qNQ== @@ -1047,100 +1067,100 @@ estree-walker "^2.0.2" picomatch "^4.0.2" -"@rollup/rollup-android-arm-eabi@4.29.1": - version "4.29.1" - resolved "https://registry.yarnpkg.com/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.29.1.tgz#9bd38df6a29afb7f0336d988bc8112af0c8816c0" - integrity sha512-ssKhA8RNltTZLpG6/QNkCSge+7mBQGUqJRisZ2MDQcEGaK93QESEgWK2iOpIDZ7k9zPVkG5AS3ksvD5ZWxmItw== - -"@rollup/rollup-android-arm64@4.29.1": - version "4.29.1" - resolved "https://registry.yarnpkg.com/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.29.1.tgz#bd1a98390e15b76eeef907175a37c5f0f9e4d214" - integrity sha512-CaRfrV0cd+NIIcVVN/jx+hVLN+VRqnuzLRmfmlzpOzB87ajixsN/+9L5xNmkaUUvEbI5BmIKS+XTwXsHEb65Ew== - -"@rollup/rollup-darwin-arm64@4.29.1": - version "4.29.1" - resolved "https://registry.yarnpkg.com/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.29.1.tgz#bc6fa8a2cc77b5f367424e5e994e3537524e6879" - integrity sha512-2ORr7T31Y0Mnk6qNuwtyNmy14MunTAMx06VAPI6/Ju52W10zk1i7i5U3vlDRWjhOI5quBcrvhkCHyF76bI7kEw== - -"@rollup/rollup-darwin-x64@4.29.1": - version "4.29.1" - resolved "https://registry.yarnpkg.com/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.29.1.tgz#76059c91f06b17406347b127df10f065283b2e61" - integrity sha512-j/Ej1oanzPjmN0tirRd5K2/nncAhS9W6ICzgxV+9Y5ZsP0hiGhHJXZ2JQ53iSSjj8m6cRY6oB1GMzNn2EUt6Ng== - -"@rollup/rollup-freebsd-arm64@4.29.1": - version "4.29.1" - resolved "https://registry.yarnpkg.com/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.29.1.tgz#83178315c0be4b4c8c1fd835e1952d2dc1eb4e6e" - integrity sha512-91C//G6Dm/cv724tpt7nTyP+JdN12iqeXGFM1SqnljCmi5yTXriH7B1r8AD9dAZByHpKAumqP1Qy2vVNIdLZqw== - -"@rollup/rollup-freebsd-x64@4.29.1": - version "4.29.1" - resolved "https://registry.yarnpkg.com/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.29.1.tgz#1ef24fa0576bf7899a0a0a649156606dbd7a0d46" - integrity sha512-hEioiEQ9Dec2nIRoeHUP6hr1PSkXzQaCUyqBDQ9I9ik4gCXQZjJMIVzoNLBRGet+hIUb3CISMh9KXuCcWVW/8w== - -"@rollup/rollup-linux-arm-gnueabihf@4.29.1": - version "4.29.1" - resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.29.1.tgz#443a6f5681bf4611caae42988994a6d8ee676216" - integrity sha512-Py5vFd5HWYN9zxBv3WMrLAXY3yYJ6Q/aVERoeUFwiDGiMOWsMs7FokXihSOaT/PMWUty/Pj60XDQndK3eAfE6A== - -"@rollup/rollup-linux-arm-musleabihf@4.29.1": - version "4.29.1" - resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.29.1.tgz#9738b27184102228637a683e5f35b22ea352394f" - integrity sha512-RiWpGgbayf7LUcuSNIbahr0ys2YnEERD4gYdISA06wa0i8RALrnzflh9Wxii7zQJEB2/Eh74dX4y/sHKLWp5uQ== - -"@rollup/rollup-linux-arm64-gnu@4.29.1": - version "4.29.1" - resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.29.1.tgz#b5e9d5e30ff36a19bedd29c715ba18a1889ff269" - integrity sha512-Z80O+taYxTQITWMjm/YqNoe9d10OX6kDh8X5/rFCMuPqsKsSyDilvfg+vd3iXIqtfmp+cnfL1UrYirkaF8SBZA== - -"@rollup/rollup-linux-arm64-musl@4.29.1": - version "4.29.1" - resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.29.1.tgz#1d8f68f0829b57f746ec03432ad046f1af014a98" - integrity sha512-fOHRtF9gahwJk3QVp01a/GqS4hBEZCV1oKglVVq13kcK3NeVlS4BwIFzOHDbmKzt3i0OuHG4zfRP0YoG5OF/rA== - -"@rollup/rollup-linux-loongarch64-gnu@4.29.1": - version "4.29.1" - resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-loongarch64-gnu/-/rollup-linux-loongarch64-gnu-4.29.1.tgz#07027feb883408e74a3002c8e50caaedd288ae38" - integrity sha512-5a7q3tnlbcg0OodyxcAdrrCxFi0DgXJSoOuidFUzHZ2GixZXQs6Tc3CHmlvqKAmOs5eRde+JJxeIf9DonkmYkw== - -"@rollup/rollup-linux-powerpc64le-gnu@4.29.1": - version "4.29.1" - resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-powerpc64le-gnu/-/rollup-linux-powerpc64le-gnu-4.29.1.tgz#544ce1b0847a9c1240425e86f33daceac7ec4e12" - integrity sha512-9b4Mg5Yfz6mRnlSPIdROcfw1BU22FQxmfjlp/CShWwO3LilKQuMISMTtAu/bxmmrE6A902W2cZJuzx8+gJ8e9w== - -"@rollup/rollup-linux-riscv64-gnu@4.29.1": - version "4.29.1" - resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.29.1.tgz#64be13d51852ec1e2dfbd25d997ed5f42f35ea6d" - integrity sha512-G5pn0NChlbRM8OJWpJFMX4/i8OEU538uiSv0P6roZcbpe/WfhEO+AT8SHVKfp8qhDQzaz7Q+1/ixMy7hBRidnQ== - -"@rollup/rollup-linux-s390x-gnu@4.29.1": - version "4.29.1" - resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.29.1.tgz#31f51e1e05c6264552d03875d9e2e673f0fd86e3" - integrity sha512-WM9lIkNdkhVwiArmLxFXpWndFGuOka4oJOZh8EP3Vb8q5lzdSCBuhjavJsw68Q9AKDGeOOIHYzYm4ZFvmWez5g== - -"@rollup/rollup-linux-x64-gnu@4.29.1": - version "4.29.1" - resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.29.1.tgz#f4c95b26f4ad69ebdb64b42f0ae4da2a0f617958" - integrity sha512-87xYCwb0cPGZFoGiErT1eDcssByaLX4fc0z2nRM6eMtV9njAfEE6OW3UniAoDhX4Iq5xQVpE6qO9aJbCFumKYQ== - -"@rollup/rollup-linux-x64-musl@4.29.1": - version "4.29.1" - resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.29.1.tgz#ab7be89192f72beb9ea6e2386186fefde4f69d82" - integrity sha512-xufkSNppNOdVRCEC4WKvlR1FBDyqCSCpQeMMgv9ZyXqqtKBfkw1yfGMTUTs9Qsl6WQbJnsGboWCp7pJGkeMhKA== - -"@rollup/rollup-win32-arm64-msvc@4.29.1": - version "4.29.1" - resolved "https://registry.yarnpkg.com/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.29.1.tgz#7f12efb8240b238346951559998802722944421e" - integrity sha512-F2OiJ42m77lSkizZQLuC+jiZ2cgueWQL5YC9tjo3AgaEw+KJmVxHGSyQfDUoYR9cci0lAywv2Clmckzulcq6ig== - -"@rollup/rollup-win32-ia32-msvc@4.29.1": - version "4.29.1" - resolved "https://registry.yarnpkg.com/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.29.1.tgz#353d14d6eee943004d129796e4feddd3aa260921" - integrity sha512-rYRe5S0FcjlOBZQHgbTKNrqxCBUmgDJem/VQTCcTnA2KCabYSWQDrytOzX7avb79cAAweNmMUb/Zw18RNd4mng== - -"@rollup/rollup-win32-x64-msvc@4.29.1": - version "4.29.1" - resolved "https://registry.yarnpkg.com/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.29.1.tgz#c82f04a09ba481e13857d6f2516e072aaa51b7f4" - integrity sha512-+10CMg9vt1MoHj6x1pxyjPSMjHTIlqs8/tBztXvPAx24SKs9jwVnKqHJumlH/IzhaPUaj3T6T6wfZr8okdXaIg== +"@rollup/rollup-android-arm-eabi@4.30.1": + version "4.30.1" + resolved "https://registry.yarnpkg.com/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.30.1.tgz#14c737dc19603a096568044eadaa60395eefb809" + integrity sha512-pSWY+EVt3rJ9fQ3IqlrEUtXh3cGqGtPDH1FQlNZehO2yYxCHEX1SPsz1M//NXwYfbTlcKr9WObLnJX9FsS9K1Q== + +"@rollup/rollup-android-arm64@4.30.1": + version "4.30.1" + resolved "https://registry.yarnpkg.com/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.30.1.tgz#9d81ea54fc5650eb4ebbc0a7d84cee331bfa30ad" + integrity sha512-/NA2qXxE3D/BRjOJM8wQblmArQq1YoBVJjrjoTSBS09jgUisq7bqxNHJ8kjCHeV21W/9WDGwJEWSN0KQ2mtD/w== + +"@rollup/rollup-darwin-arm64@4.30.1": + version "4.30.1" + resolved "https://registry.yarnpkg.com/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.30.1.tgz#29448cb1370cf678b50743d2e392be18470abc23" + integrity sha512-r7FQIXD7gB0WJ5mokTUgUWPl0eYIH0wnxqeSAhuIwvnnpjdVB8cRRClyKLQr7lgzjctkbp5KmswWszlwYln03Q== + +"@rollup/rollup-darwin-x64@4.30.1": + version "4.30.1" + resolved "https://registry.yarnpkg.com/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.30.1.tgz#0ca99741c3ed096700557a43bb03359450c7857d" + integrity sha512-x78BavIwSH6sqfP2xeI1hd1GpHL8J4W2BXcVM/5KYKoAD3nNsfitQhvWSw+TFtQTLZ9OmlF+FEInEHyubut2OA== + +"@rollup/rollup-freebsd-arm64@4.30.1": + version "4.30.1" + resolved "https://registry.yarnpkg.com/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.30.1.tgz#233f8e4c2f54ad9b719cd9645887dcbd12b38003" + integrity sha512-HYTlUAjbO1z8ywxsDFWADfTRfTIIy/oUlfIDmlHYmjUP2QRDTzBuWXc9O4CXM+bo9qfiCclmHk1x4ogBjOUpUQ== + +"@rollup/rollup-freebsd-x64@4.30.1": + version "4.30.1" + resolved "https://registry.yarnpkg.com/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.30.1.tgz#dfba762a023063dc901610722995286df4a48360" + integrity sha512-1MEdGqogQLccphhX5myCJqeGNYTNcmTyaic9S7CG3JhwuIByJ7J05vGbZxsizQthP1xpVx7kd3o31eOogfEirw== + +"@rollup/rollup-linux-arm-gnueabihf@4.30.1": + version "4.30.1" + resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.30.1.tgz#b9da54171726266c5ef4237f462a85b3c3cf6ac9" + integrity sha512-PaMRNBSqCx7K3Wc9QZkFx5+CX27WFpAMxJNiYGAXfmMIKC7jstlr32UhTgK6T07OtqR+wYlWm9IxzennjnvdJg== + +"@rollup/rollup-linux-arm-musleabihf@4.30.1": + version "4.30.1" + resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.30.1.tgz#b9db69b3f85f5529eb992936d8f411ee6d04297b" + integrity sha512-B8Rcyj9AV7ZlEFqvB5BubG5iO6ANDsRKlhIxySXcF1axXYUyqwBok+XZPgIYGBgs7LDXfWfifxhw0Ik57T0Yug== + +"@rollup/rollup-linux-arm64-gnu@4.30.1": + version "4.30.1" + resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.30.1.tgz#2550cf9bb4d47d917fd1ab4af756d7bbc3ee1528" + integrity sha512-hqVyueGxAj3cBKrAI4aFHLV+h0Lv5VgWZs9CUGqr1z0fZtlADVV1YPOij6AhcK5An33EXaxnDLmJdQikcn5NEw== + +"@rollup/rollup-linux-arm64-musl@4.30.1": + version "4.30.1" + resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.30.1.tgz#9d06b26d286c7dded6336961a2f83e48330e0c80" + integrity sha512-i4Ab2vnvS1AE1PyOIGp2kXni69gU2DAUVt6FSXeIqUCPIR3ZlheMW3oP2JkukDfu3PsexYRbOiJrY+yVNSk9oA== + +"@rollup/rollup-linux-loongarch64-gnu@4.30.1": + version "4.30.1" + resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-loongarch64-gnu/-/rollup-linux-loongarch64-gnu-4.30.1.tgz#e957bb8fee0c8021329a34ca8dfa825826ee0e2e" + integrity sha512-fARcF5g296snX0oLGkVxPmysetwUk2zmHcca+e9ObOovBR++9ZPOhqFUM61UUZ2EYpXVPN1redgqVoBB34nTpQ== + +"@rollup/rollup-linux-powerpc64le-gnu@4.30.1": + version "4.30.1" + resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-powerpc64le-gnu/-/rollup-linux-powerpc64le-gnu-4.30.1.tgz#e8585075ddfb389222c5aada39ea62d6d2511ccc" + integrity sha512-GLrZraoO3wVT4uFXh67ElpwQY0DIygxdv0BNW9Hkm3X34wu+BkqrDrkcsIapAY+N2ATEbvak0XQ9gxZtCIA5Rw== + +"@rollup/rollup-linux-riscv64-gnu@4.30.1": + version "4.30.1" + resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.30.1.tgz#7d0d40cee7946ccaa5a4e19a35c6925444696a9e" + integrity sha512-0WKLaAUUHKBtll0wvOmh6yh3S0wSU9+yas923JIChfxOaaBarmb/lBKPF0w/+jTVozFnOXJeRGZ8NvOxvk/jcw== + +"@rollup/rollup-linux-s390x-gnu@4.30.1": + version "4.30.1" + resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.30.1.tgz#c2dcd8a4b08b2f2778eceb7a5a5dfde6240ebdea" + integrity sha512-GWFs97Ruxo5Bt+cvVTQkOJ6TIx0xJDD/bMAOXWJg8TCSTEK8RnFeOeiFTxKniTc4vMIaWvCplMAFBt9miGxgkA== + +"@rollup/rollup-linux-x64-gnu@4.30.1": + version "4.30.1" + resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.30.1.tgz#183637d91456877cb83d0a0315eb4788573aa588" + integrity sha512-UtgGb7QGgXDIO+tqqJ5oZRGHsDLO8SlpE4MhqpY9Llpzi5rJMvrK6ZGhsRCST2abZdBqIBeXW6WPD5fGK5SDwg== + +"@rollup/rollup-linux-x64-musl@4.30.1": + version "4.30.1" + resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.30.1.tgz#036a4c860662519f1f9453807547fd2a11d5bb01" + integrity sha512-V9U8Ey2UqmQsBT+xTOeMzPzwDzyXmnAoO4edZhL7INkwQcaW1Ckv3WJX3qrrp/VHaDkEWIBWhRwP47r8cdrOow== + +"@rollup/rollup-win32-arm64-msvc@4.30.1": + version "4.30.1" + resolved "https://registry.yarnpkg.com/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.30.1.tgz#51cad812456e616bfe4db5238fb9c7497e042a52" + integrity sha512-WabtHWiPaFF47W3PkHnjbmWawnX/aE57K47ZDT1BXTS5GgrBUEpvOzq0FI0V/UYzQJgdb8XlhVNH8/fwV8xDjw== + +"@rollup/rollup-win32-ia32-msvc@4.30.1": + version "4.30.1" + resolved "https://registry.yarnpkg.com/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.30.1.tgz#661c8b3e4cd60f51deaa39d153aac4566e748e5e" + integrity sha512-pxHAU+Zv39hLUTdQQHUVHf4P+0C47y/ZloorHpzs2SXMRqeAWmGghzAhfOlzFHHwjvgokdFAhC4V+6kC1lRRfw== + +"@rollup/rollup-win32-x64-msvc@4.30.1": + version "4.30.1" + resolved "https://registry.yarnpkg.com/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.30.1.tgz#73bf1885ff052b82fbb0f82f8671f73c36e9137c" + integrity sha512-D6qjsXGcvhTjv0kI4fU8tUuBDF/Ueee4SVX79VfNDXZa64TfCW1Slkb6Z7O1p7vflqZjcmOVdZlqf8gvJxc6og== "@sindresorhus/merge-streams@^2.1.0": version "2.3.0" @@ -1165,9 +1185,9 @@ "@types/node" "*" "@types/node@*": - version "22.10.2" - resolved "https://registry.yarnpkg.com/@types/node/-/node-22.10.2.tgz#a485426e6d1fdafc7b0d4c7b24e2c78182ddabb9" - integrity sha512-Xxr6BBRCAOQixvonOye19wnzyDiUtTeqldOOmj3CkeblonbccA12PFwlufvRdrpjXxqnmUaeiU5EOA+7s5diUQ== + version "22.10.7" + resolved "https://registry.yarnpkg.com/@types/node/-/node-22.10.7.tgz#14a1ca33fd0ebdd9d63593ed8d3fbc882a6d28d7" + integrity sha512-V09KvXxFiutGp6B7XkpaDXlNadZxrzajcY50EuoLIpQ6WWYCSvf19lVIazzfIzQvhUN2HjX12spLojTnhuKlGg== dependencies: undici-types "~6.20.0" @@ -1186,47 +1206,47 @@ resolved "https://registry.yarnpkg.com/@types/web-bluetooth/-/web-bluetooth-0.0.20.tgz#f066abfcd1cbe66267cdbbf0de010d8a41b41597" integrity sha512-g9gZnnXVq7gM7v3tJCWV/qw7w+KeOlSHAhgF9RytFyifW6AF61hdT2ucrYhPq9hLs5JIryeupHV3qGk95dH9ow== -"@unhead/dom@1.11.14", "@unhead/dom@^1.11.14": - version "1.11.14" - resolved "https://registry.yarnpkg.com/@unhead/dom/-/dom-1.11.14.tgz#30e39d9848c964e5038c98e2de0de8bd0737d77a" - integrity sha512-FaHCWo9JR4h7PCpSRaXuMC6ifXOuBzlI0PD1MmUcxND2ayDl1d6DauIbN8TUf9TDRxNkrK1Ehb0OCXjC1ZJtrg== +"@unhead/dom@1.11.18", "@unhead/dom@^1.11.18": + version "1.11.18" + resolved "https://registry.yarnpkg.com/@unhead/dom/-/dom-1.11.18.tgz#2105b0afb567ee3f9c6b21771cfd2116bae8f37e" + integrity sha512-zQuJUw/et9zYEV0SZWTDX23IgurwMaXycAuxt4L6OgNL0T4TWP3a0J/Vm3Q02hmdNo/cPKeVBrwBdnFUXjGU4w== dependencies: - "@unhead/schema" "1.11.14" - "@unhead/shared" "1.11.14" + "@unhead/schema" "1.11.18" + "@unhead/shared" "1.11.18" -"@unhead/schema@1.11.14": - version "1.11.14" - resolved "https://registry.yarnpkg.com/@unhead/schema/-/schema-1.11.14.tgz#fec0c3947144001c12d68c96a8585abaa6771f1b" - integrity sha512-V9W9u5tF1/+TiLqxu+Qvh1ShoMDkPEwHoEo4DKdDG6ko7YlbzFfDxV6el9JwCren45U/4Vy/4Xi7j8OH02wsiA== +"@unhead/schema@1.11.18": + version "1.11.18" + resolved "https://registry.yarnpkg.com/@unhead/schema/-/schema-1.11.18.tgz#bb8f861c0872e98b500038cb926ec3755d539d33" + integrity sha512-a3TA/OJCRdfbFhcA3Hq24k1ZU1o9szicESrw8DZcGyQFacHnh84mVgnyqSkMnwgCmfN4kvjSiTBlLEHS6+wATw== dependencies: hookable "^5.5.3" zhead "^2.2.4" -"@unhead/shared@1.11.14", "@unhead/shared@^1.11.14": - version "1.11.14" - resolved "https://registry.yarnpkg.com/@unhead/shared/-/shared-1.11.14.tgz#b001403cfbdb35c8a12a9231f0734a91d2460213" - integrity sha512-41Qt4PJKYVrEGOTXgBJLRYrEu3S7n5stoB4TFC6312CIBVedXqg7voHQurn32LVDjpfJftjLa2ggCjpqdqoRDw== +"@unhead/shared@1.11.18", "@unhead/shared@^1.11.18": + version "1.11.18" + resolved "https://registry.yarnpkg.com/@unhead/shared/-/shared-1.11.18.tgz#e35a8adbf526ec640e96ec0c874df70f450d3a6c" + integrity sha512-OsupRQRxJqqnuKiL1Guqipjbl7MndD5DofvmGa3PFGu2qNPmOmH2mxGFjRBBgq2XxY1KalIHl/2I9HV6gbK8cw== dependencies: - "@unhead/schema" "1.11.14" + "@unhead/schema" "1.11.18" + packrup "^0.1.2" -"@unhead/ssr@^1.11.14": - version "1.11.14" - resolved "https://registry.yarnpkg.com/@unhead/ssr/-/ssr-1.11.14.tgz#06ad1b0ed04ba84e61fbfd8175a8402e1e38b980" - integrity sha512-JBF2f5PWPtpqBx/dan+4vL/dartSp8Nmd011zkT9qPYmizxO+/fsB1WQalbis1KszkfFatb6c4rO+hm0d6acOA== +"@unhead/ssr@^1.11.18": + version "1.11.18" + resolved "https://registry.yarnpkg.com/@unhead/ssr/-/ssr-1.11.18.tgz#19bf236b32383e61c9ab7333aa29dd7222be4c71" + integrity sha512-uaHPz0RRAb18yKeCmHyHk5QKWRk/uHpOrqSbhRXTOhbrd3Ur3gGTVaAoyUoRYKGPU5B5/pyHh3TfLw0LkfrH1A== dependencies: - "@unhead/schema" "1.11.14" - "@unhead/shared" "1.11.14" + "@unhead/schema" "1.11.18" + "@unhead/shared" "1.11.18" -"@unhead/vue@^1.11.14": - version "1.11.14" - resolved "https://registry.yarnpkg.com/@unhead/vue/-/vue-1.11.14.tgz#8d534bb7101882a70e2c0db1c49aefa3cea216d1" - integrity sha512-6nfi7FsZ936gscmj+1nUB1pybiFMFbnuEFo7B/OY2klpLWsYDUOVvpsJhbu7C3u7wkTlJXglmAk6jdd8I7WgZA== +"@unhead/vue@^1.11.18": + version "1.11.18" + resolved "https://registry.yarnpkg.com/@unhead/vue/-/vue-1.11.18.tgz#dc872a775ea6f3b2e4a5fd81e77034fa71b246a8" + integrity sha512-Jfi7t/XNBnlcauP9UTH3VHBcS69G70ikFd2e5zdgULLDRWpOlLs1sSTH1V2juNptc93DOk9RQfC5jLWbLcivFw== dependencies: - "@unhead/schema" "1.11.14" - "@unhead/shared" "1.11.14" - defu "^6.1.4" + "@unhead/schema" "1.11.18" + "@unhead/shared" "1.11.18" hookable "^5.5.3" - unhead "1.11.14" + unhead "1.11.18" "@vercel/nft@^0.27.5": version "0.27.10" @@ -1363,7 +1383,7 @@ pathe "^1.1.2" vite-hot-client "^0.2.4" -"@vue/devtools-kit@7.6.8", "@vue/devtools-kit@^7.6.8": +"@vue/devtools-kit@7.6.8": version "7.6.8" resolved "https://registry.yarnpkg.com/@vue/devtools-kit/-/devtools-kit-7.6.8.tgz#c9e98470f327d93d8d6cec8aa34cf071a1ad949b" integrity sha512-JhJ8M3sPU+v0P2iZBF2DkdmR9L0dnT5RXJabJqX6o8KtFs3tebdvfoXV2Dm3BFuqeECuMJIfF1aCzSt+WQ4wrw== @@ -1376,10 +1396,23 @@ speakingurl "^14.0.1" superjson "^2.2.1" -"@vue/devtools-shared@^7.6.8": - version "7.6.8" - resolved "https://registry.yarnpkg.com/@vue/devtools-shared/-/devtools-shared-7.6.8.tgz#ddff5e3678353a286c733df5b26d058479d521f1" - integrity sha512-9MBPO5Z3X1nYGFqTJyohl6Gmf/J7UNN1oicHdyzBVZP4jnhZ4c20MgtaHDIzWmHDHCMYVS5bwKxT3jxh7gOOKA== +"@vue/devtools-kit@^7.6.8": + version "7.7.0" + resolved "https://registry.yarnpkg.com/@vue/devtools-kit/-/devtools-kit-7.7.0.tgz#6800f57e53c06bff5c0f80622413c5e0c67ef428" + integrity sha512-5cvZ+6SA88zKC8XiuxUfqpdTwVjJbvYnQZY5NReh7qlSGPvVDjjzyEtW+gdzLXNSd8tStgOjAdMCpvDQamUXtA== + dependencies: + "@vue/devtools-shared" "^7.7.0" + birpc "^0.2.19" + hookable "^5.5.3" + mitt "^3.0.1" + perfect-debounce "^1.0.0" + speakingurl "^14.0.1" + superjson "^2.2.1" + +"@vue/devtools-shared@^7.6.8", "@vue/devtools-shared@^7.7.0": + version "7.7.0" + resolved "https://registry.yarnpkg.com/@vue/devtools-shared/-/devtools-shared-7.7.0.tgz#acc976303c5085c981b8fc866e027592dfaa9d87" + integrity sha512-jtlQY26R5thQxW9YQTpXbI0HoK0Wf9Rd4ekidOkRvSy7ChfK0kIU6vvcBtjj87/EcpeOSK49fZAicaFNJcoTcQ== dependencies: rfdc "^1.4.1" @@ -1613,9 +1646,9 @@ balanced-match@^1.0.0: integrity sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw== bare-events@^2.2.0: - version "2.5.0" - resolved "https://registry.yarnpkg.com/bare-events/-/bare-events-2.5.0.tgz#305b511e262ffd8b9d5616b056464f8e1b3329cc" - integrity sha512-/E8dDe9dsbLyh2qrZ64PEPadOQ0F4gbl1sUJOrmph7xOiIxfY8vwab/4bFLh4Y88/Hk/ujKcrQKc+ps0mv873A== + version "2.5.4" + resolved "https://registry.yarnpkg.com/bare-events/-/bare-events-2.5.4.tgz#16143d435e1ed9eafd1ab85f12b89b3357a41745" + integrity sha512-+gFfDkR8pj4/TrWCGUGWmJIkBwuxPS5F+a5yWjOHQt2hHvNZd5YLzadjmDUtFmMM4y429bnKLa8bYBMHcYdnQA== base64-js@^1.3.1: version "1.5.1" @@ -1667,9 +1700,9 @@ braces@^3.0.3, braces@~3.0.2: fill-range "^7.1.1" browserslist@^4.0.0, browserslist@^4.23.3, browserslist@^4.24.0: - version "4.24.3" - resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.24.3.tgz#5fc2725ca8fb3c1432e13dac278c7cc103e026d2" - integrity sha512-1CPmv8iobE2fyRMV97dAcMVegvvWKxmq94hkLiAkUGwKVTyDLw33K+ZxiFrREKmmps4rIw6grcCFCnTMSZ/YiA== + version "4.24.4" + resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.24.4.tgz#c6b2865a3f08bcb860a0e827389003b9fe686e4b" + integrity sha512-KDi1Ny1gSePi1vm0q4oxSF8b4DR44GF4BbmS2YdhPLOEqd8pDviZOGH/GsmRwoWJ2+5Lr085X7naowMwKHDG1A== dependencies: caniuse-lite "^1.0.30001688" electron-to-chromium "^1.5.73" @@ -1735,9 +1768,9 @@ caniuse-api@^3.0.0: lodash.uniq "^4.5.0" caniuse-lite@^1.0.0, caniuse-lite@^1.0.30001646, caniuse-lite@^1.0.30001688: - version "1.0.30001690" - resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001690.tgz#f2d15e3aaf8e18f76b2b8c1481abde063b8104c8" - integrity sha512-5ExiE3qQN6oF8Clf8ifIDcMRCRE/dMGcETG/XGMD8/XiXm6HXQgQTh1yZYLXXpSOsEUlJm1Xr7kGULZTuGtP/w== + version "1.0.30001692" + resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001692.tgz#4585729d95e6b95be5b439da6ab55250cd125bf9" + integrity sha512-A95VKan0kdtrsnMubMKxEKUKImOPSuCpYgxSQBo036P5YYgVIcOYJEgt/txJWqObiRQeISNCfef9nvlQ0vbV7A== chalk@^4.1.1: version "4.1.2" @@ -1882,10 +1915,10 @@ confbox@^0.1.7, confbox@^0.1.8: resolved "https://registry.yarnpkg.com/confbox/-/confbox-0.1.8.tgz#820d73d3b3c82d9bd910652c5d4d599ef8ff8b06" integrity sha512-RMtmw0iFkeR4YV+fUOSucriAQNb9g8zFR52MWCtl+cCZOFRNL6zeB395vPzFhEjjn4fMxXudmELnl/KF/WrK6w== -consola@^3.2.3, consola@^3.3.0, consola@^3.3.1: - version "3.3.3" - resolved "https://registry.yarnpkg.com/consola/-/consola-3.3.3.tgz#0dd8a2314b0f7bf18a49064138ad685f3346543d" - integrity sha512-Qil5KwghMzlqd51UXM0b6fyaGHtOC22scxrwrz4A2882LyUMwQjnvaedN1HAeXzphspQ6CpHkzMAWxBTUruDLg== +consola@^3.2.3, consola@^3.3.1, consola@^3.3.3, consola@^3.4.0: + version "3.4.0" + resolved "https://registry.yarnpkg.com/consola/-/consola-3.4.0.tgz#4cfc9348fd85ed16a17940b3032765e31061ab88" + integrity sha512-EiPU8G6dQG0GFHNR8ljnZFki/8a+cQwEQ+7wpxdChl02Q8HXlwEZWD5lqAF8vC2sEC3Tehr8hy7vErz88LHyUA== convert-source-map@^2.0.0: version "2.0.0" @@ -1905,9 +1938,9 @@ copy-anything@^3.0.2: is-what "^4.1.8" core-js@^3.26.1: - version "3.39.0" - resolved "https://registry.yarnpkg.com/core-js/-/core-js-3.39.0.tgz#57f7647f4d2d030c32a72ea23a0555b2eaa30f83" - integrity sha512-raM0ew0/jJUqkJ0E6e8UDtl+y/7ktFivgWvqw8dNSQeNWoSDLvQ1H/RN3aPXB9tBd4/FhyR4RDPGhsNIMsAn7g== + version "3.40.0" + resolved "https://registry.yarnpkg.com/core-js/-/core-js-3.40.0.tgz#2773f6b06877d8eda102fc42f828176437062476" + integrity sha512-7vsMc/Lty6AGnn7uFpYT56QesI5D2Y/UkgKounk87OP9Z2H9Z8kj6jzcSGAxFmUtDOS0ntK6lbQz+Nsa0Jj6mQ== core-util-is@~1.0.0: version "1.0.3" @@ -1933,9 +1966,9 @@ croner@^9.0.0: integrity sha512-onMB0OkDjkXunhdW9htFjEhqrD54+M94i6ackoUkjHKbRnXdyEyKRelp4nJ1kAz32+s27jP1FsebpJCVl0BsvA== cronstrue@^2.49.0, cronstrue@^2.52.0: - version "2.52.0" - resolved "https://registry.yarnpkg.com/cronstrue/-/cronstrue-2.52.0.tgz#00af1a8dcf76a1dece149e4416db823105b28cdb" - integrity sha512-NKgHbWkSZXJUcaBHSsyzC8eegD6bBd4O0oCI6XMIJ+y4Bq3v4w7sY3wfWoKPuVlq9pQHRB6od0lmKpIqi8TlKA== + version "2.53.0" + resolved "https://registry.yarnpkg.com/cronstrue/-/cronstrue-2.53.0.tgz#5bbcd7483636b99379480f624faef5056f3efbd8" + integrity sha512-CkAcaI94xL8h6N7cGxgXfR5D7oV2yVtDzB9vMZP8tIgPyEv/oc/7nq9rlk7LMxvc3N+q6LKZmNLCVxJRpyEg8A== cross-spawn@^7.0.0, cross-spawn@^7.0.3: version "7.0.6" @@ -2175,9 +2208,9 @@ domhandler@^5.0.2, domhandler@^5.0.3: domelementtype "^2.3.0" domutils@^3.0.1: - version "3.2.1" - resolved "https://registry.yarnpkg.com/domutils/-/domutils-3.2.1.tgz#b39f4c390a1ae6f6a2c56a5f5a16d6438b6bce28" - integrity sha512-xWXmuRnN9OMP6ptPd2+H0cCbcYBULa5YDTbMm/2lvkWvNA3O4wcW+GvzooqBuNM8yy6pl3VIAeJTUUWUbfI5Fw== + version "3.2.2" + resolved "https://registry.yarnpkg.com/domutils/-/domutils-3.2.2.tgz#edbfe2b668b0c1d97c24baf0f1062b132221bc78" + integrity sha512-6kZKyUajlDuqlHKVX1w7gyslj9MPIXzIFiz/rGu35uC1wMi+kMhQwGhl4lt9unC9Vb9INnY9Z3/ZA3+FhASLaw== dependencies: dom-serializer "^2.0.0" domelementtype "^2.3.0" @@ -2211,9 +2244,9 @@ ee-first@1.1.1: integrity sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow== electron-to-chromium@^1.5.73: - version "1.5.76" - resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.5.76.tgz#db20295c5061b68f07c8ea4dfcbd701485d94a3d" - integrity sha512-CjVQyG7n7Sr+eBXE86HIulnL5N8xZY1sgmOPGuq/F0Rr0FJq63lg0kEtOIDfZBk44FnDLf6FUJ+dsJcuiUDdDQ== + version "1.5.83" + resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.5.83.tgz#3f74078f0c83e24bf7e692eaa855a998d1bec34f" + integrity sha512-LcUDPqSt+V0QmI47XLzZrz5OqILSMGsPFkDYus22rIbgorSvBYEFqq854ltTmUdHkY92FSdAAvsh4jWEULMdfQ== emoji-regex@^8.0.0: version "8.0.0" @@ -2415,16 +2448,16 @@ fast-fifo@^1.2.0, fast-fifo@^1.3.2: resolved "https://registry.yarnpkg.com/fast-fifo/-/fast-fifo-1.3.2.tgz#286e31de96eb96d38a97899815740ba2a4f3640c" integrity sha512-/d9sfos4yxzpwkDkuN7k2SqFKtYNmCTzgfEpz82x34IM9/zc8KGxQoXg1liNC/izpRM/MBdt44Nmx41ZWqk+FQ== -fast-glob@^3.2.7, fast-glob@^3.3.2: - version "3.3.2" - resolved "https://registry.yarnpkg.com/fast-glob/-/fast-glob-3.3.2.tgz#a904501e57cfdd2ffcded45e99a54fef55e46129" - integrity sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow== +fast-glob@^3.2.7, fast-glob@^3.3.2, fast-glob@^3.3.3: + version "3.3.3" + resolved "https://registry.yarnpkg.com/fast-glob/-/fast-glob-3.3.3.tgz#d06d585ce8dba90a16b0505c543c3ccfb3aeb818" + integrity sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg== dependencies: "@nodelib/fs.stat" "^2.0.2" "@nodelib/fs.walk" "^1.2.3" glob-parent "^5.1.2" merge2 "^1.3.0" - micromatch "^4.0.4" + micromatch "^4.0.8" fast-npm-meta@^0.2.2: version "0.2.2" @@ -2439,9 +2472,9 @@ fastq@^1.6.0: reusify "^1.0.4" fdir@^6.2.0, fdir@^6.4.2: - version "6.4.2" - resolved "https://registry.yarnpkg.com/fdir/-/fdir-6.4.2.tgz#ddaa7ce1831b161bc3657bb99cb36e1622702689" - integrity sha512-KnhMXsKSPZlAhp7+IjUkRZKPb4fUyccpDrdFXbi4QL1qkmFh9kVY09Yox+n4MaOb3lHZ1Tv829C3oaaXoMYPDQ== + version "6.4.3" + resolved "https://registry.yarnpkg.com/fdir/-/fdir-6.4.3.tgz#011cdacf837eca9b811c89dbb902df714273db72" + integrity sha512-PMXmW2y1hDDfTSRc9gaXIuCCRpuoz3Kaz8cUelp3smouvfT632ozg2vrT6lJsHKKOF59YLbOGfAWGUcKEfRMQw== file-uri-to-path@1.0.0: version "1.0.0" @@ -2487,9 +2520,9 @@ fresh@0.5.2: integrity sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q== fs-extra@^11.1.0, fs-extra@^11.2.0: - version "11.2.0" - resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-11.2.0.tgz#e70e17dfad64232287d01929399e0ea7c86b0e5b" - integrity sha512-PmDi3uwK5nFuXh7XDTlVnS17xJS7vW36is2+w3xcv8SVxiB4NyATf4ctkVY5bkSjX0Y4nbvZCq1/EjtEyr9ktw== + version "11.3.0" + resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-11.3.0.tgz#0daced136bbaf65a555a326719af931adc7a314d" + integrity sha512-Z4XaCL6dUDHfP/jT25jJKMmtxvuwbkrD1vNSMFlo9lNLY2c5FHYSQgHPRZUjAB26TpDEoW9HCOgplrdbaPV/ew== dependencies: graceful-fs "^4.2.0" jsonfile "^6.0.1" @@ -2517,6 +2550,11 @@ function-bind@^1.1.2: resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.2.tgz#2c02d864d97f3ea6c8830c464cbd11ab6eab7a1c" integrity sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA== +fuse.js@^7.0.0: + version "7.0.0" + resolved "https://registry.yarnpkg.com/fuse.js/-/fuse.js-7.0.0.tgz#6573c9fcd4c8268e403b4fc7d7131ffcf99a9eb2" + integrity sha512-14F4hBIxqKvD4Zz/XjDc3y94mNZN6pRv3U13Udo0lNLCWRBUsrMv2xwcF/y/Z5sV6+FQW+/ow68cHpm4sunt8Q== + gensync@^1.0.0-beta.2: version "1.0.0-beta.2" resolved "https://registry.yarnpkg.com/gensync/-/gensync-1.0.0-beta.2.tgz#32a6ee76c3d7f52d46b2b1ae5d93fea8580a25e0" @@ -2643,13 +2681,13 @@ gzip-size@^7.0.0: dependencies: duplexer "^0.1.2" -h3@^1.12.0, h3@^1.13.0: - version "1.13.0" - resolved "https://registry.yarnpkg.com/h3/-/h3-1.13.0.tgz#b5347a8936529794b6754b440e26c0ab8a60dceb" - integrity sha512-vFEAu/yf8UMUcB4s43OaDaigcqpQd14yanmOsn+NcRX3/guSKncyE2rOYhq8RIchgJrPSs/QiIddnTTR1ddiAg== +h3@^1.12.0, h3@^1.13.0, h3@^1.13.1: + version "1.13.1" + resolved "https://registry.yarnpkg.com/h3/-/h3-1.13.1.tgz#915966340b0b0ebeca1acc39bd2ecae08ae331f6" + integrity sha512-u/z6Z4YY+ANZ05cRRfsFJadTBrNA6e3jxdU+AN5UCbZSZEUwgHiwjvUEe0k1NoQmAvQmETwr+xB5jd7mhCJuIQ== dependencies: cookie-es "^1.2.2" - crossws ">=0.2.0 <0.4.0" + crossws "^0.3.1" defu "^6.1.4" destr "^2.0.3" iron-webcrypto "^1.2.1" @@ -2672,9 +2710,9 @@ hasown@^2.0.2: function-bind "^1.1.2" hls.js@^1.4.14: - version "1.5.18" - resolved "https://registry.yarnpkg.com/hls.js/-/hls.js-1.5.18.tgz#f0279072c31ba763efc08b6c7dff0f10f0703db0" - integrity sha512-znxR+2jecWluu/0KOBqUcvVyAB5tLff10vjMGrpAlz1eFY+ZhF1bY3r82V+Bk7WJdk03iTjtja9KFFz5BrqjSA== + version "1.5.19" + resolved "https://registry.yarnpkg.com/hls.js/-/hls.js-1.5.19.tgz#bc8471a7c712f1314b04b2be4639dd273819d3dc" + integrity sha512-C020dKWEJcyvLnrqsFKW4q6D/6IEzKWdhktIS5bgoyEFE8lHgrFBq4RIngdy113abJOlIruhv8qjg7UX8hwxOw== hookable@^5.5.3: version "5.5.3" @@ -2711,9 +2749,9 @@ https-proxy-agent@^7.0.4, https-proxy-agent@^7.0.5: debug "4" httpxy@^0.1.5: - version "0.1.5" - resolved "https://registry.yarnpkg.com/httpxy/-/httpxy-0.1.5.tgz#fd2401206e0b5d919aeda25e967ece0f1a6c8569" - integrity sha512-hqLDO+rfststuyEUTWObQK6zHEEmZ/kaIP2/zclGGZn6X8h/ESTWg+WKecQ/e5k4nPswjzZD+q2VqZIbr15CoQ== + version "0.1.6" + resolved "https://registry.yarnpkg.com/httpxy/-/httpxy-0.1.6.tgz#74a11e435bbcd6ff712763d6de9372659f7f08f8" + integrity sha512-GxJLI6oJZ3NbJl/vDlPmTCtP4WHwboNhGLHOcgf/3ia1QC5sdLglWbRHZwQjzjPuiCyw7MWwpwbsUfRDQlOdeg== human-signals@^4.3.0: version "4.3.1" @@ -2735,10 +2773,10 @@ ignore@^5.2.4: resolved "https://registry.yarnpkg.com/ignore/-/ignore-5.3.2.tgz#3cd40e729f3643fd87cb04e50bf0eb722bc596f5" integrity sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g== -ignore@^7.0.0: - version "7.0.0" - resolved "https://registry.yarnpkg.com/ignore/-/ignore-7.0.0.tgz#52da780b009bd0845d1f9dd4d8ae6a7569ae73c4" - integrity sha512-lcX8PNQygAa22u/0BysEY8VhaFRzlOkvdlKczDPnJvrkJD1EuqzEky5VYYKM2iySIuaVIDv9N190DfSreSLw2A== +ignore@^7.0.3: + version "7.0.3" + resolved "https://registry.yarnpkg.com/ignore/-/ignore-7.0.3.tgz#397ef9315dfe0595671eefe8b633fec6943ab733" + integrity sha512-bAH5jbK/F3T3Jls4I0SO1hmPR0dKU0a7+SY6n1yzRtG54FLO8d6w/nxLFX2Nb7dBu6cCWXPaAME6cYqFUMmuCA== image-meta@^0.2.1: version "0.2.1" @@ -3072,6 +3110,14 @@ local-pkg@^0.5.0, local-pkg@^0.5.1: mlly "^1.7.3" pkg-types "^1.2.1" +local-pkg@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/local-pkg/-/local-pkg-1.0.0.tgz#a8d14dd41e78884f199ecd8b3eedaf0d376e2167" + integrity sha512-bbgPw/wmroJsil/GgL4qjDzs5YLTBMQ99weRsok1XCDccQeehbHA/I1oRvk2NPtr7KGZgT/Y5tPRnAtMqeG2Kg== + dependencies: + mlly "^1.7.3" + pkg-types "^1.3.0" + lodash.defaults@^4.2.0: version "4.2.0" resolved "https://registry.yarnpkg.com/lodash.defaults/-/lodash.defaults-4.2.0.tgz#d09178716ffea4dde9e5fb7b37f6f0802274580c" @@ -3162,7 +3208,7 @@ merge2@^1.3.0: resolved "https://registry.yarnpkg.com/merge2/-/merge2-1.4.1.tgz#4368892f885e907455a6fd7dc55c0c9d404990ae" integrity sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg== -micromatch@^4.0.4, micromatch@^4.0.5: +micromatch@^4.0.5, micromatch@^4.0.8: version "4.0.8" resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-4.0.8.tgz#d66fa18f3a47076789320b9b1af32bd86d9fa202" integrity sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA== @@ -3259,14 +3305,14 @@ mkdirp@^3.0.1: resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-3.0.1.tgz#e44e4c5607fb279c168241713cc6e0fea9adcb50" integrity sha512-+NsyUUAZDmo6YVHzL/stxSu3t9YS1iljliy3BSDrXJ/dkn1KYdmtZODGGjLcc9XLgVVpH4KshHB8XmZgMhaBXg== -mlly@^1.3.0, mlly@^1.6.1, mlly@^1.7.1, mlly@^1.7.2, mlly@^1.7.3: - version "1.7.3" - resolved "https://registry.yarnpkg.com/mlly/-/mlly-1.7.3.tgz#d86c0fcd8ad8e16395eb764a5f4b831590cee48c" - integrity sha512-xUsx5n/mN0uQf4V548PKQ+YShA4/IW0KI1dZhrNrPCLG+xizETbHTkOa1f8/xut9JRPp8kQuMnz0oqwkTiLo/A== +mlly@^1.3.0, mlly@^1.6.1, mlly@^1.7.1, mlly@^1.7.2, mlly@^1.7.3, mlly@^1.7.4: + version "1.7.4" + resolved "https://registry.yarnpkg.com/mlly/-/mlly-1.7.4.tgz#3d7295ea2358ec7a271eaa5d000a0f84febe100f" + integrity sha512-qmdSIPC4bDJXgZTCR7XosJiNKySV7O215tsPtDN9iEO/7q/76b/ijtgRu/+epFXSJhijtTCCGp3DWS549P3xKw== dependencies: acorn "^8.14.0" - pathe "^1.1.2" - pkg-types "^1.2.1" + pathe "^2.0.1" + pkg-types "^1.3.0" ufo "^1.5.4" moment@^2.30.1: @@ -3289,7 +3335,7 @@ ms@2.1.3, ms@^2.1.3: resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.3.tgz#574c8138ce1d2b5861f0b44579dbadd60c6615b2" integrity sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA== -nanoid@^3.3.7: +nanoid@^3.3.8: version "3.3.8" resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-3.3.8.tgz#b1be3030bee36aaff18bacb375e5cce521684baf" integrity sha512-WNLf5Sd8oZxOm+TzppcYk8gVOgP+l58xNy58D0nbUnOxOWRWvlcCV4kUF7ltmI6PsrLl/BgKEyS4mqsGChFN0w== @@ -3453,32 +3499,28 @@ nth-check@^2.0.1: dependencies: boolbase "^1.0.0" -nuxi@^3.17.2: - version "3.17.2" - resolved "https://registry.yarnpkg.com/nuxi/-/nuxi-3.17.2.tgz#72cad260a8c332cae053b9ca588328138efcfa73" - integrity sha512-JDVtBBwEe9VjVkhxwR/crtGJnyLHzvl2F1pjtglekjTVeiMThfhQHcvsI/u007gBAfPpmaCIdRGnoeTF4VKS8w== - nuxt@^3.11.2: - version "3.15.0" - resolved "https://registry.yarnpkg.com/nuxt/-/nuxt-3.15.0.tgz#a2ca73369900e89d57ac122a6a43d3c31ef8d404" - integrity sha512-pjP/2zEjr57ensZZ1F4b7KldocM9S4SOtukgi9zau1OFlyolUmEgMFbHnwmEKqzuZ1OPTaRS3/1S6B7GUVbbRg== + version "3.15.2" + resolved "https://registry.yarnpkg.com/nuxt/-/nuxt-3.15.2.tgz#8d8db22fa86422a2309660f94bd5bcddc11363aa" + integrity sha512-1EiQ5wYYVhgkRyaMCyuc4R5lhJtOPJTdOe3LwYNbIol3pmcO1urhNDNKfhiy9zdcA3G14zzN0W/+TqXXidchRw== dependencies: + "@nuxt/cli" "^3.20.0" "@nuxt/devalue" "^2.0.2" - "@nuxt/devtools" "^1.6.4" - "@nuxt/kit" "3.15.0" - "@nuxt/schema" "3.15.0" - "@nuxt/telemetry" "^2.6.2" - "@nuxt/vite-builder" "3.15.0" - "@unhead/dom" "^1.11.14" - "@unhead/shared" "^1.11.14" - "@unhead/ssr" "^1.11.14" - "@unhead/vue" "^1.11.14" + "@nuxt/devtools" "^1.7.0" + "@nuxt/kit" "3.15.2" + "@nuxt/schema" "3.15.2" + "@nuxt/telemetry" "^2.6.4" + "@nuxt/vite-builder" "3.15.2" + "@unhead/dom" "^1.11.18" + "@unhead/shared" "^1.11.18" + "@unhead/ssr" "^1.11.18" + "@unhead/vue" "^1.11.18" "@vue/shared" "^3.5.13" acorn "8.14.0" c12 "^2.0.1" chokidar "^4.0.3" compatx "^0.1.8" - consola "^3.3.1" + consola "^3.4.0" cookie-es "^1.2.2" defu "^6.1.4" destr "^2.0.3" @@ -3488,40 +3530,39 @@ nuxt@^3.11.2: escape-string-regexp "^5.0.0" estree-walker "^3.0.3" globby "^14.0.2" - h3 "^1.13.0" + h3 "^1.13.1" hookable "^5.5.3" - ignore "^7.0.0" + ignore "^7.0.3" impound "^0.2.0" jiti "^2.4.2" klona "^2.0.6" knitwork "^1.2.0" magic-string "^0.30.17" - mlly "^1.7.3" + mlly "^1.7.4" nanotar "^0.1.1" nitropack "^2.10.4" - nuxi "^3.17.2" nypm "^0.4.1" ofetch "^1.4.1" ohash "^1.1.4" - pathe "^1.1.2" + pathe "^2.0.1" perfect-debounce "^1.0.0" - pkg-types "^1.2.1" + pkg-types "^1.3.1" radix3 "^1.1.2" scule "^1.3.0" semver "^7.6.3" std-env "^3.8.0" - strip-literal "^2.1.1" + strip-literal "^3.0.0" tinyglobby "0.2.10" ufo "^1.5.4" ultrahtml "^1.5.3" uncrypto "^0.1.3" unctx "^2.4.1" unenv "^1.10.0" - unhead "^1.11.14" - unimport "^3.14.5" - unplugin "^2.1.0" + unhead "^1.11.18" + unimport "^3.14.6" + unplugin "^2.1.2" unplugin-vue-router "^0.10.9" - unstorage "^1.14.1" + unstorage "^1.14.4" untyped "^1.5.2" vue "^3.5.13" vue-bundle-renderer "^2.1.1" @@ -3607,11 +3648,11 @@ open@^8.4.0: is-wsl "^2.2.0" openapi-typescript@^7.4.2: - version "7.4.4" - resolved "https://registry.yarnpkg.com/openapi-typescript/-/openapi-typescript-7.4.4.tgz#77fd70c275d40cf98fb4a68a96e09dc38859cbb9" - integrity sha512-7j3nktnRzlQdlHnHsrcr6Gqz8f80/RhfA2I8s1clPI+jkY0hLNmnYVKBfuUEli5EEgK1B6M+ibdS5REasPlsUw== + version "7.5.2" + resolved "https://registry.yarnpkg.com/openapi-typescript/-/openapi-typescript-7.5.2.tgz#b7b40087aaba171af5cab83c60a1dc1255b8ed65" + integrity sha512-W/QXuQz0Fa3bGY6LKoqTCgrSX+xI/ST+E5RXo2WBmp3WwgXCWKDJPHv5GZmElF4yLCccnqYsakBDOJikHZYGRw== dependencies: - "@redocly/openapi-core" "^1.25.9" + "@redocly/openapi-core" "^1.27.0" ansi-colors "^4.1.3" change-case "^5.4.4" parse-json "^8.1.0" @@ -3623,11 +3664,16 @@ package-json-from-dist@^1.0.0: resolved "https://registry.yarnpkg.com/package-json-from-dist/-/package-json-from-dist-1.0.1.tgz#4f1471a010827a86f94cfd9b0727e36d267de505" integrity sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw== -package-manager-detector@^0.2.7: +package-manager-detector@^0.2.8: version "0.2.8" resolved "https://registry.yarnpkg.com/package-manager-detector/-/package-manager-detector-0.2.8.tgz#f5ace2dbd37666af54e5acec11bc37c8450f72d0" integrity sha512-ts9KSdroZisdvKMWVAVCXiKqnqNfXz4+IbrBG8/BWx/TR5le+jfenvoBuIZ6UWM9nz47W7AbD9qYfAwfWMIwzA== +packrup@^0.1.2: + version "0.1.2" + resolved "https://registry.yarnpkg.com/packrup/-/packrup-0.1.2.tgz#7e6c50e5b79a1e68cd717e79fd06d40abb8f1583" + integrity sha512-ZcKU7zrr5GlonoS9cxxrb5HVswGnyj6jQvwFBa6p5VFw7G71VAHcUKL5wyZSU/ECtPM/9gacWxy2KFQKt1gMNA== + parse-git-config@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/parse-git-config/-/parse-git-config-3.0.0.tgz#4a2de08c7b74a2555efa5ae94d40cd44302a6132" @@ -3703,12 +3749,17 @@ pathe@^1.1.1, pathe@^1.1.2: resolved "https://registry.yarnpkg.com/pathe/-/pathe-1.1.2.tgz#6c4cb47a945692e48a1ddd6e4094d170516437ec" integrity sha512-whLdWMYL2TwI08hn8/ZqAbrVemu0LNaNNJZX73O6qaIdCTfXutsLhMkjdENX0qhsQ9uIimo4/aQOmXkoon2nDQ== +pathe@^2.0.0, pathe@^2.0.1: + version "2.0.2" + resolved "https://registry.yarnpkg.com/pathe/-/pathe-2.0.2.tgz#5ed86644376915b3c7ee4d00ac8c348d671da3a5" + integrity sha512-15Ztpk+nov8DR524R4BF7uEuzESgzUEAV4Ah7CUMNGXdE5ELuvxElxGXndBl32vMSsWa1jpNf22Z+Er3sKwq+w== + perfect-debounce@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/perfect-debounce/-/perfect-debounce-1.0.0.tgz#9c2e8bc30b169cc984a58b7d5b28049839591d2a" integrity sha512-xCy9V055GLEqoFaHoC1SoLIaLmWctgCUaBaWxDZ7/Zx4CTyX7cJQLJOok/orfjZAh9kEYpjJa4d0KcJmCbctZA== -picocolors@^1.0.0, picocolors@^1.0.1, picocolors@^1.1.0, picocolors@^1.1.1: +picocolors@^1.0.0, picocolors@^1.0.1, picocolors@^1.1.1: version "1.1.1" resolved "https://registry.yarnpkg.com/picocolors/-/picocolors-1.1.1.tgz#3d321af3eab939b083c8f929a1d12cda81c26b6b" integrity sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA== @@ -3723,14 +3774,14 @@ picomatch@^4.0.2: resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-4.0.2.tgz#77c742931e8f3b8820946c76cd0c1f13730d1dab" integrity sha512-M7BAV6Rlcy5u+m6oPhAPFgJTzAioX/6B0DxyvDlo9l8+T3nLKbrczg2WLUyzd45L8RqfUMyGPzekbMvX2Ldkwg== -pkg-types@^1.0.3, pkg-types@^1.2.0, pkg-types@^1.2.1: - version "1.3.0" - resolved "https://registry.yarnpkg.com/pkg-types/-/pkg-types-1.3.0.tgz#53d915eb99485798c554ad8eb2dc2af7c03006eb" - integrity sha512-kS7yWjVFCkIw9hqdJBoMxDdzEngmkr5FXeWZZfQ6GoYacjVnsW6l2CcYW/0ThD0vF4LPJgVYnrg4d0uuhwYQbg== +pkg-types@^1.0.3, pkg-types@^1.2.0, pkg-types@^1.2.1, pkg-types@^1.3.0, pkg-types@^1.3.1: + version "1.3.1" + resolved "https://registry.yarnpkg.com/pkg-types/-/pkg-types-1.3.1.tgz#bd7cc70881192777eef5326c19deb46e890917df" + integrity sha512-/Jm5M4RvtBFVkKWRu2BLUTNP8/M2a+UwuAX+ae4770q1qVGtfjG+WTCupoZixokjmHiry8uI+dlY8KXYV5HVVQ== dependencies: confbox "^0.1.8" - mlly "^1.7.3" - pathe "^1.1.2" + mlly "^1.7.4" + pathe "^2.0.1" pluralize@^8.0.0: version "8.0.0" @@ -3749,11 +3800,11 @@ plyr@^3.7.8: url-polyfill "^1.1.12" postcss-calc@^10.0.2: - version "10.0.2" - resolved "https://registry.yarnpkg.com/postcss-calc/-/postcss-calc-10.0.2.tgz#15f01635a27b9d38913a98c4ef2877f5b715b439" - integrity sha512-DT/Wwm6fCKgpYVI7ZEWuPJ4az8hiEHtCUeYjZXqU7Ou4QqYh1Df2yCQ7Ca6N7xqKPFkxN3fhf+u9KSoOCJNAjg== + version "10.1.0" + resolved "https://registry.yarnpkg.com/postcss-calc/-/postcss-calc-10.1.0.tgz#82548b9d52891b87cf6181a445bea4b78e2eedfb" + integrity sha512-uQ/LDGsf3mgsSUEXmAt3VsCSHR3aKqtEIkmB+4PhzYwRYOW5MZs/GhCCFpsOtJJkP6EC6uGipbrnaTjqaJZcJw== dependencies: - postcss-selector-parser "^6.1.2" + postcss-selector-parser "^7.0.0" postcss-value-parser "^4.2.0" postcss-colormin@^7.0.2: @@ -3940,6 +3991,14 @@ postcss-selector-parser@^6.1.2: cssesc "^3.0.0" util-deprecate "^1.0.2" +postcss-selector-parser@^7.0.0: + version "7.0.0" + resolved "https://registry.yarnpkg.com/postcss-selector-parser/-/postcss-selector-parser-7.0.0.tgz#41bd8b56f177c093ca49435f65731befe25d6b9c" + integrity sha512-9RbEr1Y7FFfptd/1eEdntyjMwLeghW1bHX9GWjXo19vx4ytPQhANltvVxDggzJl7mnWM+dX28kb6cyS/4iQjlQ== + dependencies: + cssesc "^3.0.0" + util-deprecate "^1.0.2" + postcss-svgo@^7.0.1: version "7.0.1" resolved "https://registry.yarnpkg.com/postcss-svgo/-/postcss-svgo-7.0.1.tgz#2b63571d8e9568384df334bac9917baff4d23f58" @@ -3960,12 +4019,12 @@ postcss-value-parser@^4.2.0: resolved "https://registry.yarnpkg.com/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz#723c09920836ba6d3e5af019f92bc0971c02e514" integrity sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ== -postcss@^8.4.43, postcss@^8.4.48, postcss@^8.4.49: - version "8.4.49" - resolved "https://registry.yarnpkg.com/postcss/-/postcss-8.4.49.tgz#4ea479048ab059ab3ae61d082190fabfd994fe19" - integrity sha512-OCVPnIObs4N29kxTjzLfUryOkvZEq+pf8jTF0lg8E7uETuWHA+v7j3c/xJmiqpX450191LlmZfUKkXxkTry7nA== +postcss@^8.4.43, postcss@^8.4.48, postcss@^8.4.49, postcss@^8.5.1: + version "8.5.1" + resolved "https://registry.yarnpkg.com/postcss/-/postcss-8.5.1.tgz#e2272a1f8a807fafa413218245630b5db10a3214" + integrity sha512-6oz2beyjc5VMn/KV1pPw8fliQkhBXrVn1Z3TVyqZxU8kZpzEKhBdmCFqI6ZbmGtamQvQGuU1sgPTk8ZrXDD7jQ== dependencies: - nanoid "^3.3.7" + nanoid "^3.3.8" picocolors "^1.1.1" source-map-js "^1.2.1" @@ -4051,9 +4110,9 @@ readable-stream@^2.0.5: util-deprecate "~1.0.1" readable-stream@^4.0.0: - version "4.6.0" - resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-4.6.0.tgz#ce412dfb19c04efde1c5936d99c27f37a1ff94c9" - integrity sha512-cbAdYt0VcnpN2Bekq7PU+k363ZRsPwJoEEJOEtSJQlJXzwaxt3FIo/uL+KeDSGIjJqtkwyge4KQgD2S2kd+CQw== + version "4.7.0" + resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-4.7.0.tgz#cedbd8a1146c13dfff8dab14068028d58c15ac91" + integrity sha512-oIGGmcpTLwPga8Bn6/Z75SVaH1z5dUut2ibSyAMVhmUggWpmDn2dapB0n7f8nwaSiRtepAsfJyfXIO5DCVAODg== dependencies: abort-controller "^3.0.0" buffer "^6.0.3" @@ -4069,9 +4128,9 @@ readdir-glob@^1.1.2: minimatch "^5.1.0" readdirp@^4.0.1: - version "4.0.2" - resolved "https://registry.yarnpkg.com/readdirp/-/readdirp-4.0.2.tgz#388fccb8b75665da3abffe2d8f8ed59fe74c230a" - integrity sha512-yDMz9g+VaZkqBYS/ozoBJwaBhTbZo3UNYQHNRw1D3UFQB8oHB4uS/tAODO+ZLjGWmUbKnIlOWO+aaIiAxrUWHA== + version "4.1.1" + resolved "https://registry.yarnpkg.com/readdirp/-/readdirp-4.1.1.tgz#bd115327129672dc47f87408f05df9bd9ca3ef55" + integrity sha512-h80JrZu/MHUZCyHu5ciuoI0+WxsCxzxJTILn6Fs8rxSnFPh+UVHYfeIxK1nVGugMqkfC4vJcBOYbkfkwYK0+gw== readdirp@~3.6.0: version "3.6.0" @@ -4133,10 +4192,10 @@ rimraf@^5.0.5: dependencies: glob "^10.3.7" -rollup-plugin-visualizer@^5.12.0: - version "5.13.1" - resolved "https://registry.yarnpkg.com/rollup-plugin-visualizer/-/rollup-plugin-visualizer-5.13.1.tgz#fa49320cd23c8642f856f8bd45ddaf3e10a5b023" - integrity sha512-vMg8i6BprL8aFm9DKvL2c8AwS8324EgymYQo9o6E26wgVvwMhsJxS37aNL6ZsU7X9iAcMYwdME7gItLfG5fwJg== +rollup-plugin-visualizer@^5.12.0, rollup-plugin-visualizer@^5.13.1: + version "5.14.0" + resolved "https://registry.yarnpkg.com/rollup-plugin-visualizer/-/rollup-plugin-visualizer-5.14.0.tgz#be82d43fb3c644e396e2d50ac8a53d354022d57c" + integrity sha512-VlDXneTDaKsHIw8yzJAFWtrzguoJ/LnQ+lMpoVfYJ3jJF4Ihe5oYLAqLklIK/35lgUY+1yEzCkHyZ1j4A5w5fA== dependencies: open "^8.4.0" picomatch "^4.0.2" @@ -4144,31 +4203,31 @@ rollup-plugin-visualizer@^5.12.0: yargs "^17.5.1" rollup@^4.20.0, rollup@^4.23.0, rollup@^4.24.3: - version "4.29.1" - resolved "https://registry.yarnpkg.com/rollup/-/rollup-4.29.1.tgz#a9aaaece817e5f778489e5bf82e379cc8a5c05bc" - integrity sha512-RaJ45M/kmJUzSWDs1Nnd5DdV4eerC98idtUOVr6FfKcgxqvjwHmxc5upLF9qZU9EpsVzzhleFahrT3shLuJzIw== + version "4.30.1" + resolved "https://registry.yarnpkg.com/rollup/-/rollup-4.30.1.tgz#d5c3d066055259366cdc3eb6f1d051c5d6afaf74" + integrity sha512-mlJ4glW020fPuLi7DkM/lN97mYEZGWeqBnrljzN0gs7GLctqX3lNWxKQ7Gl712UAX+6fog/L3jh4gb7R6aVi3w== dependencies: "@types/estree" "1.0.6" optionalDependencies: - "@rollup/rollup-android-arm-eabi" "4.29.1" - "@rollup/rollup-android-arm64" "4.29.1" - "@rollup/rollup-darwin-arm64" "4.29.1" - "@rollup/rollup-darwin-x64" "4.29.1" - "@rollup/rollup-freebsd-arm64" "4.29.1" - "@rollup/rollup-freebsd-x64" "4.29.1" - "@rollup/rollup-linux-arm-gnueabihf" "4.29.1" - "@rollup/rollup-linux-arm-musleabihf" "4.29.1" - "@rollup/rollup-linux-arm64-gnu" "4.29.1" - "@rollup/rollup-linux-arm64-musl" "4.29.1" - "@rollup/rollup-linux-loongarch64-gnu" "4.29.1" - "@rollup/rollup-linux-powerpc64le-gnu" "4.29.1" - "@rollup/rollup-linux-riscv64-gnu" "4.29.1" - "@rollup/rollup-linux-s390x-gnu" "4.29.1" - "@rollup/rollup-linux-x64-gnu" "4.29.1" - "@rollup/rollup-linux-x64-musl" "4.29.1" - "@rollup/rollup-win32-arm64-msvc" "4.29.1" - "@rollup/rollup-win32-ia32-msvc" "4.29.1" - "@rollup/rollup-win32-x64-msvc" "4.29.1" + "@rollup/rollup-android-arm-eabi" "4.30.1" + "@rollup/rollup-android-arm64" "4.30.1" + "@rollup/rollup-darwin-arm64" "4.30.1" + "@rollup/rollup-darwin-x64" "4.30.1" + "@rollup/rollup-freebsd-arm64" "4.30.1" + "@rollup/rollup-freebsd-x64" "4.30.1" + "@rollup/rollup-linux-arm-gnueabihf" "4.30.1" + "@rollup/rollup-linux-arm-musleabihf" "4.30.1" + "@rollup/rollup-linux-arm64-gnu" "4.30.1" + "@rollup/rollup-linux-arm64-musl" "4.30.1" + "@rollup/rollup-linux-loongarch64-gnu" "4.30.1" + "@rollup/rollup-linux-powerpc64le-gnu" "4.30.1" + "@rollup/rollup-linux-riscv64-gnu" "4.30.1" + "@rollup/rollup-linux-s390x-gnu" "4.30.1" + "@rollup/rollup-linux-x64-gnu" "4.30.1" + "@rollup/rollup-linux-x64-musl" "4.30.1" + "@rollup/rollup-win32-arm64-msvc" "4.30.1" + "@rollup/rollup-win32-ia32-msvc" "4.30.1" + "@rollup/rollup-win32-x64-msvc" "4.30.1" fsevents "~2.3.2" run-applescript@^7.0.0: @@ -4444,6 +4503,13 @@ strip-literal@^2.1.1: dependencies: js-tokens "^9.0.1" +strip-literal@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/strip-literal/-/strip-literal-3.0.0.tgz#ce9c452a91a0af2876ed1ae4e583539a353df3fc" + integrity sha512-TcccoMhJOM3OebGhSBEmp3UZ2SfDMZUEBdRA/9ynfLi8yYajyWX3JiXArcJt4Umh4vISpspkQIY8ZZoCqjbviA== + dependencies: + js-tokens "^9.0.1" + stylehacks@^7.0.4: version "7.0.4" resolved "https://registry.yarnpkg.com/stylehacks/-/stylehacks-7.0.4.tgz#9c21f7374f4bccc0082412b859b3c89d77d3277c" @@ -4559,7 +4625,7 @@ tiny-invariant@^1.1.0: resolved "https://registry.yarnpkg.com/tiny-invariant/-/tiny-invariant-1.3.3.tgz#46680b7a873a0d5d10005995eb90a70d74d60127" integrity sha512-+FbBPE1o9QAYvviau/qC5SE3caw21q3xkvWKBtja5vgqOWIHHJ3ioaq1VPfn/Szqctz2bU/oYeKd9/z5BL+PVg== -tinyexec@^0.3.1: +tinyexec@^0.3.1, tinyexec@^0.3.2: version "0.3.2" resolved "https://registry.yarnpkg.com/tinyexec/-/tinyexec-0.3.2.tgz#941794e657a85e496577995c6eef66f53f42b3d2" integrity sha512-KQQR9yN7R5+OSwaK0XQoj22pwHoTlgYqmUscPYoknOoWCWfj/5/ABTMRi69FrKU5ffPVh5QcFikpWJI/P1ocHA== @@ -4600,9 +4666,9 @@ type-fest@^0.21.3: integrity sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w== type-fest@^4.18.2, type-fest@^4.7.1: - version "4.31.0" - resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-4.31.0.tgz#a3de630c96eb77c281b6ba2affa5dae5fb3c326c" - integrity sha512-yCxltHW07Nkhv/1F6wWBr8kz+5BGMfP+RbRSYFnegVb0qV/UMT0G0ElBloPVerqn4M2ZV80Ir1FtCcYv1cT6vQ== + version "4.32.0" + resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-4.32.0.tgz#55bacdd6f2cf1392b7e9cde894e9b1d726807e97" + integrity sha512-rfgpoi08xagF3JSdtJlCwMq9DGNDE0IMh3Mkpc1wUypg9vPi786AiqeBBKcqvIkq42azsBM85N490fyZjeUftw== ufo@^1.1.2, ufo@^1.5.4: version "1.5.4" @@ -4645,14 +4711,14 @@ unenv@^1.10.0: node-fetch-native "^1.6.4" pathe "^1.1.2" -unhead@1.11.14, unhead@^1.11.14: - version "1.11.14" - resolved "https://registry.yarnpkg.com/unhead/-/unhead-1.11.14.tgz#9be7c432a74fa299462d7e87b2a2c0b0e9c48e01" - integrity sha512-XmXW0aZyX9kGk9ejCKCSvv/J4T3Rt4hoAe2EofM+nhG+zwZ7AArUMK/0F/fj6FTkfgY0u0/JryE00qUDULgygA== +unhead@1.11.18, unhead@^1.11.18: + version "1.11.18" + resolved "https://registry.yarnpkg.com/unhead/-/unhead-1.11.18.tgz#a89b78262ac6aae3130cb64e3a93d0bd56c40115" + integrity sha512-TWgGUoZMpYe2yJwY6jZ0/9kpQT18ygr2h5lI6cUXdfD9UzDc0ytM9jGaleSYkj9guJWXkk7izYBnzJvxl8mRvQ== dependencies: - "@unhead/dom" "1.11.14" - "@unhead/schema" "1.11.14" - "@unhead/shared" "1.11.14" + "@unhead/dom" "1.11.18" + "@unhead/schema" "1.11.18" + "@unhead/shared" "1.11.18" hookable "^5.5.3" unicorn-magic@^0.1.0: @@ -4660,25 +4726,25 @@ unicorn-magic@^0.1.0: resolved "https://registry.yarnpkg.com/unicorn-magic/-/unicorn-magic-0.1.0.tgz#1bb9a51c823aaf9d73a8bfcd3d1a23dde94b0ce4" integrity sha512-lRfVq8fE8gz6QMBuDM6a+LO3IAzTi05H6gCVaUpir2E1Rwpo4ZUog45KpNXKC/Mn3Yb9UDuHumeFTo9iV/D9FQ== -unimport@^3.13.1, unimport@^3.14.5: - version "3.14.5" - resolved "https://registry.yarnpkg.com/unimport/-/unimport-3.14.5.tgz#6433dd21423edad6e225e61fbf8ea969bcc8bde1" - integrity sha512-tn890SwFFZxqaJSKQPPd+yygfKSATbM8BZWW1aCR2TJBTs1SDrmLamBueaFtYsGjHtQaRgqEbQflOjN2iW12gA== +unimport@^3.13.1, unimport@^3.14.5, unimport@^3.14.6: + version "3.14.6" + resolved "https://registry.yarnpkg.com/unimport/-/unimport-3.14.6.tgz#f01170aa2fb94c4f97b22c0ac2822ef7e8e0726d" + integrity sha512-CYvbDaTT04Rh8bmD8jz3WPmHYZRG/NnvYVzwD6V1YAlvvKROlAeNDUBhkBGzNav2RKaeuXvlWYaa1V4Lfi/O0g== dependencies: - "@rollup/pluginutils" "^5.1.3" + "@rollup/pluginutils" "^5.1.4" acorn "^8.14.0" escape-string-regexp "^5.0.0" estree-walker "^3.0.3" - fast-glob "^3.3.2" - local-pkg "^0.5.1" - magic-string "^0.30.14" - mlly "^1.7.3" - pathe "^1.1.2" + fast-glob "^3.3.3" + local-pkg "^1.0.0" + magic-string "^0.30.17" + mlly "^1.7.4" + pathe "^2.0.1" picomatch "^4.0.2" - pkg-types "^1.2.1" + pkg-types "^1.3.0" scule "^1.3.0" strip-literal "^2.1.1" - unplugin "^1.16.0" + unplugin "^1.16.1" universalify@^2.0.0: version "2.0.1" @@ -4713,15 +4779,15 @@ unplugin@2.0.0-beta.1: acorn "^8.14.0" webpack-virtual-modules "^0.6.2" -unplugin@^1.10.0, unplugin@^1.14.1, unplugin@^1.16.0: - version "1.16.0" - resolved "https://registry.yarnpkg.com/unplugin/-/unplugin-1.16.0.tgz#ca0f248bf8798cd752dd02e5b381223b737cef72" - integrity sha512-5liCNPuJW8dqh3+DM6uNM2EI3MLLpCKp/KY+9pB5M2S2SR2qvvDHhKgBOaTWEbZTAws3CXfB0rKTIolWKL05VQ== +unplugin@^1.10.0, unplugin@^1.14.1, unplugin@^1.16.1: + version "1.16.1" + resolved "https://registry.yarnpkg.com/unplugin/-/unplugin-1.16.1.tgz#a844d2e3c3b14a4ac2945c42be80409321b61199" + integrity sha512-4/u/j4FrCKdi17jaxuJA0jClGxB1AvU2hw/IuayPc4ay1XGaJs/rbb4v5WKwAjNifjmXK9PIFyuPiaK8azyR9w== dependencies: acorn "^8.14.0" webpack-virtual-modules "^0.6.2" -unplugin@^2.1.0: +unplugin@^2.1.0, unplugin@^2.1.2: version "2.1.2" resolved "https://registry.yarnpkg.com/unplugin/-/unplugin-2.1.2.tgz#3a0939061c0076f1a8178e5d4223df63ee62c741" integrity sha512-Q3LU0e4zxKfRko1wMV2HmP8lB9KWislY7hxXpxd+lGx0PRInE4vhMBVEZwpdVYHvtqzhSrzuIfErsob6bQfCzw== @@ -4729,7 +4795,7 @@ unplugin@^2.1.0: acorn "^8.14.0" webpack-virtual-modules "^0.6.2" -unstorage@^1.13.1, unstorage@^1.14.1: +unstorage@^1.13.1, unstorage@^1.14.4: version "1.14.4" resolved "https://registry.yarnpkg.com/unstorage/-/unstorage-1.14.4.tgz#620dd68997a3245fca1e04c0171335817525bc3d" integrity sha512-1SYeamwuYeQJtJ/USE1x4l17LkmQBzg7deBJ+U9qOBoHo15d1cDxG4jM31zKRgF7pG0kirZy4wVMX6WL6Zoscg== @@ -4779,12 +4845,12 @@ unwasm@^0.3.9: unplugin "^1.10.0" update-browserslist-db@^1.1.1: - version "1.1.1" - resolved "https://registry.yarnpkg.com/update-browserslist-db/-/update-browserslist-db-1.1.1.tgz#80846fba1d79e82547fb661f8d141e0945755fe5" - integrity sha512-R8UzCaa9Az+38REPiJ1tXlImTJXlVfgHZsglwBD/k6nj76ctsH1E3q4doGrukiLQd3sGQYu56r5+lo5r94l29A== + version "1.1.2" + resolved "https://registry.yarnpkg.com/update-browserslist-db/-/update-browserslist-db-1.1.2.tgz#97e9c96ab0ae7bcac08e9ae5151d26e6bc6b5580" + integrity sha512-PPypAm5qvlD7XMZC3BujecnaOxwhrtoFR+Dqkk5Aa/6DssiH0ibKoketaj9w8LP7Bont1rYeoV5plxD7RTEPRg== dependencies: escalade "^3.2.0" - picocolors "^1.1.0" + picocolors "^1.1.1" uqr@^0.1.2: version "0.1.2" @@ -4888,10 +4954,10 @@ vite@^5.0.0: optionalDependencies: fsevents "~2.3.3" -vite@^6.0.5: - version "6.0.6" - resolved "https://registry.yarnpkg.com/vite/-/vite-6.0.6.tgz#a851674fcff55b0c1962f72082354b8802e48505" - integrity sha512-NSjmUuckPmDU18bHz7QZ+bTYhRR0iA72cs2QAxCqDpafJ0S6qetco0LB3WW2OxlMHS0JmAv+yZ/R3uPmMyGTjQ== +vite@^6.0.7: + version "6.0.7" + resolved "https://registry.yarnpkg.com/vite/-/vite-6.0.7.tgz#f0f8c120733b04af52b4a1e3e7cb54eb851a799b" + integrity sha512-RDt8r/7qx9940f8FcOIAH9PTViRrghKaK2K1jY3RaAURrEUbm9Du1mJ72G+jlhtG3WwodnfzY8ORQZbBavZEAQ== dependencies: esbuild "^0.24.2" postcss "^8.4.49" @@ -5083,9 +5149,9 @@ yaml-ast-parser@0.0.43: integrity sha512-2PTINUwsRqSd+s8XxKaJWQlUuEMHJQyEuh2edBbW8KNJz0SJPwUSD2zRWqezFEdN7IzAgeuYHFUCF7o8zRdZ0A== yaml@^2.6.1: - version "2.6.1" - resolved "https://registry.yarnpkg.com/yaml/-/yaml-2.6.1.tgz#42f2b1ba89203f374609572d5349fb8686500773" - integrity sha512-7r0XPzioN/Q9kXBro/XPnA6kznR73DHq+GXh5ON7ZozRO6aMjbmiBuKste2wslTFkC5d1dw0GooOCepZXJ2SAg== + version "2.7.0" + resolved "https://registry.yarnpkg.com/yaml/-/yaml-2.7.0.tgz#aef9bb617a64c937a9a748803786ad8d3ffe1e98" + integrity sha512-+hSoy/QHluxmC9kCIJyL/uyFmLmc+e5CFR5Wa+bpIhIj85LVb9ZH2nVnqrHoSvKogwODv0ClqZkmiSSaIH5LTA== yargs-parser@^21.1.1: version "21.1.1" diff --git a/src/API/Backend/Stale.php b/src/API/Backend/Stale.php index af866715..1c6979fa 100644 --- a/src/API/Backend/Stale.php +++ b/src/API/Backend/Stale.php @@ -5,11 +5,14 @@ namespace App\API\Backend; use App\API\Backend\Index as backendIndex; +use App\Libs\Attributes\Route\Delete; use App\Libs\Attributes\Route\Get; +use App\Libs\Database\DatabaseInterface as iDB; use App\Libs\DataUtil; use App\Libs\Entity\StateInterface as iState; use App\Libs\Enums\Http\Status; use App\Libs\Exceptions\RuntimeException; +use App\Libs\Mappers\Import\DirectMapper; use App\Libs\Mappers\Import\MemoryMapper; use App\Libs\Mappers\Import\ReadOnlyMapper; use App\Libs\Traits\APITraits; @@ -26,8 +29,8 @@ public function __construct(private readonly ReadOnlyMapper $mapper, private rea ini_set('memory_limit', '-1'); } - #[Get(backendIndex::URL . '/{name:backend}/stale/{id}[/]', name: 'backend.stale')] - public function __invoke(iRequest $request, string $name, string|int $id): iResponse + #[Get(backendIndex::URL . '/{name:backend}/stale/{id}[/]', name: 'backend.stale.list')] + public function listContent(iRequest $request, string $name, string|int $id): iResponse { if (empty($name)) { return api_error('Invalid value for name path parameter.', Status::BAD_REQUEST); @@ -37,29 +40,69 @@ public function __invoke(iRequest $request, string $name, string|int $id): iResp return api_error('Invalid value for id path parameter.', Status::BAD_REQUEST); } - if (null === $this->getBackend(name: $name)) { - return api_error(r("Backend '{name}' not found.", ['name' => $name]), Status::NOT_FOUND); + $params = DataUtil::fromArray($request->getQueryParams()); + + try { + $data = $this->getContent( + name: $name, + id: $id, + ignore: (bool)$params->get('ignore', false), + timeout: (int)$params->get('timeout', 0), + ); + $data['items'] = array_map(fn($item) => self::formatEntity($item), $data['items']); + } catch (RuntimeException $e) { + return api_error($e->getMessage(), Status::NOT_FOUND); } - $params = DataUtil::fromArray($request->getQueryParams()); + return api_response(Status::OK, $data); + } - $backendOpts = $list = []; + #[Delete(backendIndex::URL . '/{name:backend}/stale/{id}[/]', name: 'backend.stale.delete')] + public function deleteContent( + iRequest $request, + DirectMapper $mapper, + iDB $db, + string $name, + string|int $id + ): iResponse { + if (empty($name)) { + return api_error('Invalid value for name path parameter.', Status::BAD_REQUEST); + } - if ($params->get('timeout')) { - $backendOpts = ag_set($backendOpts, 'client.timeout', (float)$params->get('timeout')); + if (empty($id)) { + return api_error('Invalid value for id path parameter.', Status::BAD_REQUEST); } - try { - $client = $this->getClient(name: $name, config: $backendOpts); - } catch (RuntimeException $e) { - return api_error($e->getMessage(), Status::NOT_FOUND); + $data = DataUtil::fromRequest($request); + $ids = $data->get('ids', []); + if (false === is_array($ids) || empty($ids)) { + return api_error('No items to delete.', Status::BAD_REQUEST); + } + + $mapper->loadData(); + + return api_message('Removed stale references.', Status::OK); + } + + private function getContent(string $name, string|int $id, bool $ignore = false, int|float $timeout = 0): array + { + if (null === $this->getBackend(name: $name)) { + throw new RuntimeException(r("Backend '{name}' not found.", ['name' => $name])); } + $backendOpts = $list = []; + + if (0 !== $timeout) { + $backendOpts = ag_set($backendOpts, 'client.timeout', (float)$timeout); + } + + $client = $this->getClient(name: $name, config: $backendOpts); + $remote = cacheableItem( - 'remote-data-' . $name, + "remote-data-{$id}-{$name}", fn() => array_map(fn($item) => ag($item->getMetadata($item->via), iState::COLUMN_ID), $client->getLibraryContent($id)) - , ignoreCache: (bool)$params->get('ignore', false) + , ignoreCache: $ignore ); $this->local->loadData(); @@ -103,7 +146,7 @@ public function __invoke(iRequest $request, string $name, string|int $id): iResp break; } - return api_response(Status::OK, [ + return [ 'backend' => [ 'library' => $libraryInfo, 'name' => $client->getContext()->backendName, @@ -113,7 +156,7 @@ public function __invoke(iRequest $request, string $name, string|int $id): iResp 'local' => $localCount, 'stale' => count($list), ], - 'items' => array_map(fn($item) => self::formatEntity($item), $list), - ]); + 'items' => $list, + ]; } } From 3314a527c2937367b3961bc0153b2edab2eb66dd Mon Sep 17 00:00:00 2001 From: ArabCoders Date: Sat, 18 Jan 2025 02:06:35 +0300 Subject: [PATCH 6/6] Remove debug code. --- src/Commands/State/SyncCommand.php | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/Commands/State/SyncCommand.php b/src/Commands/State/SyncCommand.php index 32bf7388..3aac1b80 100644 --- a/src/Commands/State/SyncCommand.php +++ b/src/Commands/State/SyncCommand.php @@ -312,7 +312,7 @@ protected function process(iInput $input, iOutput $output): int 'results' => arrayToString($this->usersList($users)), ]); - foreach (array_reverse($users) as $user) { + foreach ($users as $user) { $this->queue->reset(); $this->mapper->reset(); @@ -378,7 +378,6 @@ protected function process(iInput $input, iOutput $output): int 'peak' => getPeakMemoryUsage(), ], ]); - exit(1); } return self::SUCCESS;