From 359936b6094bde2ea40d0e8d834034cdef646cf1 Mon Sep 17 00:00:00 2001 From: Konstantin Obenland Date: Tue, 28 Oct 2025 12:13:59 -0500 Subject: [PATCH 1/4] Refactor: Reorganize integration loader and Stream integration - Reorganize integrations in load.php in alphabetical order - Move Stream integration into dedicated stream/ folder structure - Create Stream wrapper class to encapsulate Stream-related functionality - Move Stream_Connector class to stream/class-connector.php with updated namespace - Move stream registration and filter functions into Stream class methods - Consolidate BuddyPress initialization with other integrations - Update test file to use new Stream\Connector namespace --- integration/load.php | 177 ++++++++---------- .../class-connector.php} | 51 +++-- integration/stream/class-stream.php | 58 ++++++ .../class-test-stream-connector.php | 30 +-- 4 files changed, 178 insertions(+), 138 deletions(-) rename integration/{class-stream-connector.php => stream/class-connector.php} (83%) create mode 100644 integration/stream/class-stream.php diff --git a/integration/load.php b/integration/load.php index 848b60e5aa..af17d6fd0a 100644 --- a/integration/load.php +++ b/integration/load.php @@ -16,36 +16,37 @@ */ function plugin_init() { /** - * Adds Classic Editor support. + * Adds Akismet support. * - * This class handles the compatibility with the Classic Editor plugin - * and sites without block editor support. + * This class handles the compatibility with the Akismet plugin. * - * @see https://wordpress.org/plugins/classic-editor/ + * @see https://wordpress.org/plugins/akismet/ */ - if ( class_exists( '\Classic_Editor' ) || ! site_supports_blocks() ) { - Classic_Editor::init(); + if ( \defined( 'AKISMET_VERSION' ) ) { + Akismet::init(); } /** - * Adds WebFinger (plugin) support. + * Adds BuddyPress support. * - * This class handles the compatibility with the WebFinger plugin - * and coordinates the internal WebFinger implementation. + * This class handles the compatibility with BuddyPress. + * Hooks into bp_include to ensure BuddyPress is fully loaded. * - * @see https://wordpress.org/plugins/webfinger/ + * @see https://buddypress.org/ */ - Webfinger::init(); + \add_action( 'bp_include', array( __NAMESPACE__ . '\Buddypress', 'init' ), 0 ); /** - * Adds NodeInfo (plugin) support. + * Adds Classic Editor support. * - * This class handles the compatibility with the NodeInfo plugin - * and coordinates the internal NodeInfo implementation. + * This class handles the compatibility with the Classic Editor plugin + * and sites without block editor support. * - * @see https://wordpress.org/plugins/nodeinfo/ + * @see https://wordpress.org/plugins/classic-editor/ */ - Nodeinfo::init(); + if ( class_exists( '\Classic_Editor' ) || ! site_supports_blocks() ) { + Classic_Editor::init(); + } /** * Adds Enable Mastodon Apps support. @@ -58,17 +59,6 @@ function plugin_init() { Enable_Mastodon_Apps::init(); } - /** - * Adds OpenGraph support. - * - * This class handles the compatibility with the OpenGraph plugin. - * - * @see https://wordpress.org/plugins/opengraph/ - */ - if ( '1' === \get_option( 'activitypub_use_opengraph', '1' ) ) { - Opengraph::init(); - } - /** * Adds Jetpack support. * @@ -81,15 +71,13 @@ function plugin_init() { } /** - * Adds Akismet support. + * Adds LiteSpeed Cache support. * - * This class handles the compatibility with the Akismet plugin. + * The check for whether LiteSpeed Cache is loaded and initialized happens inside Litespeed_Cache::init(). * - * @see https://wordpress.org/plugins/akismet/ + * @see https://wordpress.org/plugins/litespeed-cache/ */ - if ( \defined( 'AKISMET_VERSION' ) ) { - Akismet::init(); - } + Litespeed_Cache::init(); /** * Adds Multisite Language Switcher support. @@ -102,6 +90,27 @@ function plugin_init() { Multisite_Language_Switcher::init(); } + /** + * Adds NodeInfo (plugin) support. + * + * This class handles the compatibility with the NodeInfo plugin + * and coordinates the internal NodeInfo implementation. + * + * @see https://wordpress.org/plugins/nodeinfo/ + */ + Nodeinfo::init(); + + /** + * Adds OpenGraph support. + * + * This class handles the compatibility with the OpenGraph plugin. + * + * @see https://wordpress.org/plugins/opengraph/ + */ + if ( '1' === \get_option( 'activitypub_use_opengraph', '1' ) ) { + Opengraph::init(); + } + /** * Adds Seriously Simple Podcasting support. * @@ -127,48 +136,65 @@ function ( $transformer, $data, $object_class ) { } /** - * Adds WPML Multilingual CMS (plugin) support. + * Adds Stream support. * - * This class handles the compatibility with the WPML plugin. + * This class handles the compatibility with the Stream plugin. * - * @see https://wpml.org/ + * @see https://wordpress.org/plugins/stream/ */ - if ( \defined( 'ICL_SITEPRESS_VERSION' ) ) { - WPML::init(); - } + Stream\Stream::init(); - if ( \class_exists( 'WP_Rest_Cache_Plugin\Includes\Plugin' ) ) { - WP_Rest_Cache::init(); - } + /** + * Adds Surge support. + * + * Only load code that needs Surge to run once Surge is loaded and initialized. + * + * @see https://wordpress.org/plugins/surge/ + */ + Surge::init(); /** - * Adds Yoast SEO support. + * Adds WebFinger (plugin) support. * - * This class handles the compatibility with Yoast SEO. + * This class handles the compatibility with the WebFinger plugin + * and coordinates the internal WebFinger implementation. * - * @see https://wordpress.org/plugins/wordpress-seo/ + * @see https://wordpress.org/plugins/webfinger/ */ - if ( \defined( 'WPSEO_VERSION' ) ) { - Yoast_Seo::init(); + Webfinger::init(); + + /** + * Adds WP REST Cache support. + * + * This class handles the compatibility with the WP REST Cache plugin. + * + * @see https://wordpress.org/plugins/wp-rest-cache/ + */ + if ( \class_exists( 'WP_Rest_Cache_Plugin\Includes\Plugin' ) ) { + WP_Rest_Cache::init(); } /** - * Load the Surge integration. + * Adds WPML Multilingual CMS (plugin) support. * - * Only load code that needs Surge to run once Surge is loaded and initialized. + * This class handles the compatibility with the WPML plugin. * - * @see https://wordpress.org/plugins/surge/ + * @see https://wpml.org/ */ - Surge::init(); + if ( \defined( 'ICL_SITEPRESS_VERSION' ) ) { + WPML::init(); + } /** - * Load the LiteSpeed Cache integration. + * Adds Yoast SEO support. * - * The check for whether LiteSpeed Cache is loaded and initialized happens inside Litespeed_Cache::init(). + * This class handles the compatibility with Yoast SEO. * - * @see https://wordpress.org/plugins/litespeed-cache/ + * @see https://wordpress.org/plugins/wordpress-seo/ */ - Litespeed_Cache::init(); + if ( \defined( 'WPSEO_VERSION' ) ) { + Yoast_Seo::init(); + } } \add_action( 'plugins_loaded', __NAMESPACE__ . '\plugin_init' ); @@ -179,44 +205,3 @@ function ( $transformer, $data, $object_class ) { // Register activation and deactivation hooks for LiteSpeed Cache integration. \register_activation_hook( ACTIVITYPUB_PLUGIN_FILE, array( __NAMESPACE__ . '\LiteSpeed_Cache', 'add_htaccess_rules' ) ); \register_deactivation_hook( ACTIVITYPUB_PLUGIN_FILE, array( __NAMESPACE__ . '\LiteSpeed_Cache', 'remove_htaccess_rules' ) ); - - -/** - * Register the Stream Connector for ActivityPub. - * - * @param array $classes The Stream connectors. - * - * @return array The Stream connectors with the ActivityPub connector. - */ -function register_stream_connector( $classes ) { - $class = new Stream_Connector(); - - if ( method_exists( $class, 'is_dependency_satisfied' ) && $class->is_dependency_satisfied() ) { - $classes[] = $class; - } - - return $classes; -} -add_filter( 'wp_stream_connectors', __NAMESPACE__ . '\register_stream_connector' ); - -// Excluded ActivityPub post types from the Stream. -add_filter( - 'wp_stream_posts_exclude_post_types', - function ( $post_types ) { - $post_types[] = 'ap_actor'; - $post_types[] = 'ap_extrafield'; - $post_types[] = 'ap_extrafield_blog'; - $post_types[] = 'ap_post'; - - return $post_types; - } -); - -/** - * Load the BuddyPress integration. - * - * Only load code that needs BuddyPress to run once BP is loaded and initialized. - * - * @see https://buddypress.org/ - */ -add_action( 'bp_include', array( __NAMESPACE__ . '\Buddypress', 'init' ), 0 ); diff --git a/integration/class-stream-connector.php b/integration/stream/class-connector.php similarity index 83% rename from integration/class-stream-connector.php rename to integration/stream/class-connector.php index a99f684e62..8331e8834e 100644 --- a/integration/class-stream-connector.php +++ b/integration/stream/class-connector.php @@ -5,7 +5,7 @@ * @package Activitypub */ -namespace Activitypub\Integration; +namespace Activitypub\Integration\Stream; use Activitypub\Collection\Actors; @@ -19,7 +19,7 @@ * * @see https://wordpress.org/plugins/stream/ */ -class Stream_Connector extends \WP_Stream\Connector { +class Connector extends \WP_Stream\Connector { /** * Connector slug. * @@ -45,7 +45,7 @@ class Stream_Connector extends \WP_Stream\Connector { * @return string */ public function get_label() { - return __( 'ActivityPub', 'activitypub' ); + return \__( 'ActivityPub', 'activitypub' ); } /** @@ -64,7 +64,7 @@ public function get_context_labels() { */ public function get_action_labels() { return array( - 'processed' => __( 'Processed', 'activitypub' ), + 'processed' => \__( 'Processed', 'activitypub' ), ); } @@ -80,25 +80,25 @@ public function get_action_labels() { */ public function action_links( $links, $record ) { if ( 'processed' === $record->action ) { - $error = json_decode( $record->get_meta( 'error', true ), true ); + $error = \json_decode( $record->get_meta( 'error', true ), true ); if ( $error ) { - $message = sprintf( + $message = \sprintf( '
%1$s
%2$s
', - __( 'Inbox Error', 'activitypub' ), - wp_json_encode( $error ) + \__( 'Inbox Error', 'activitypub' ), + \wp_json_encode( $error ) ); $links[ $message ] = ''; } - $debug = json_decode( $record->get_meta( 'debug', true ), true ); + $debug = \json_decode( $record->get_meta( 'debug', true ), true ); if ( $debug ) { - $message = sprintf( + $message = \sprintf( '
%1$s
%2$s
', - __( 'Debug', 'activitypub' ), - wp_json_encode( $debug ) + \__( 'Debug', 'activitypub' ), + \wp_json_encode( $debug ) ); $links[ $message ] = ''; @@ -149,13 +149,13 @@ public function callback_activitypub_outbox_processing_complete( $inboxes, $json $outbox_data = $this->prepare_outbox_data_for_response( $outbox_item ); $this->log( - sprintf( + \sprintf( // translators: %s is a URL. - __( 'Outbox processing complete: %s', 'activitypub' ), + \__( 'Outbox processing complete: %s', 'activitypub' ), $outbox_data['title'] ), array( - 'debug' => wp_json_encode( + 'debug' => \wp_json_encode( array( 'actor_id' => $actor_id, 'outbox_item_id' => $outbox_item_id, @@ -183,13 +183,10 @@ public function callback_activitypub_outbox_processing_batch_complete( $inboxes, $outbox_data = $this->prepare_outbox_data_for_response( $outbox_item ); $this->log( - sprintf( - // translators: %s is a URL. - __( 'Outbox processing batch complete: %s', 'activitypub' ), - $outbox_data['title'] - ), + // translators: %s is a URL. + \sprintf( \__( 'Outbox processing batch complete: %s', 'activitypub' ), $outbox_data['title'] ), array( - 'debug' => wp_json_encode( + 'debug' => \wp_json_encode( array( 'actor_id' => $actor_id, 'outbox_item_id' => $outbox_item_id, @@ -216,9 +213,9 @@ protected function prepare_outbox_data_for_response( $outbox_item ) { $object_type = $outbox_item->post_type; $object_title = $outbox_item->post_title; - $post_id = url_to_postid( $outbox_item->post_title ); + $post_id = \url_to_postid( $outbox_item->post_title ); if ( $post_id ) { - $post = get_post( $post_id ); + $post = \get_post( $post_id ); $object_id = $post_id; $object_type = $post->post_type; @@ -226,7 +223,7 @@ protected function prepare_outbox_data_for_response( $outbox_item ) { } else { $comment_id = url_to_commentid( $outbox_item->post_title ); if ( $comment_id ) { - $comment = get_comment( $comment_id ); + $comment = \get_comment( $comment_id ); $object_id = $comment_id; $object_type = 'comments'; @@ -238,11 +235,11 @@ protected function prepare_outbox_data_for_response( $outbox_item ) { $object_type = 'profiles'; if ( $author_id ) { - $object_title = get_userdata( $author_id )->display_name; + $object_title = \get_userdata( $author_id )->display_name; } elseif ( Actors::BLOG_USER_ID === $author_id ) { - $object_title = __( 'Blog User', 'activitypub' ); + $object_title = \__( 'Blog User', 'activitypub' ); } elseif ( Actors::APPLICATION_USER_ID === $author_id ) { - $object_title = __( 'Application User', 'activitypub' ); + $object_title = \__( 'Application User', 'activitypub' ); } } } diff --git a/integration/stream/class-stream.php b/integration/stream/class-stream.php new file mode 100644 index 0000000000..56730b30ce --- /dev/null +++ b/integration/stream/class-stream.php @@ -0,0 +1,58 @@ +is_dependency_satisfied() ) { + $classes[] = $class; + } + + return $classes; + } + + /** + * Exclude ActivityPub post types from the Stream. + * + * @param array $post_types The post types to exclude. + * + * @return array The post types to exclude with ActivityPub post types. + */ + public static function exclude_post_types( $post_types ) { + $post_types[] = 'ap_actor'; + $post_types[] = 'ap_extrafield'; + $post_types[] = 'ap_extrafield_blog'; + $post_types[] = 'ap_post'; + + return $post_types; + } +} diff --git a/tests/phpunit/tests/integration/class-test-stream-connector.php b/tests/phpunit/tests/integration/class-test-stream-connector.php index 2c6a067c28..414e1cd4cf 100644 --- a/tests/phpunit/tests/integration/class-test-stream-connector.php +++ b/tests/phpunit/tests/integration/class-test-stream-connector.php @@ -7,19 +7,19 @@ namespace Activitypub\Tests\Integration; -use Activitypub\Integration\Stream_Connector; +use Activitypub\Integration\Stream\Connector; /** * Test Stream Connector Integration class. * * @group integration - * @coversDefaultClass \Activitypub\Integration\Stream_Connector + * @coversDefaultClass \Activitypub\Integration\Stream\Connector */ class Test_Stream_Connector extends \WP_UnitTestCase { /** * Stream Connector instance. * - * @var Stream_Connector + * @var Connector */ protected $stream_connector; @@ -95,13 +95,13 @@ protected function is_stream_available() { */ public function set_up() { parent::set_up(); - $this->stream_connector = new \Activitypub\Integration\Stream_Connector(); + $this->stream_connector = new \Activitypub\Integration\Stream\Connector(); } /** * Test the Stream connector registration hook behavior. * - * @covers \Activitypub\Integration\register_stream_connector + * @covers \Activitypub\Integration\Stream\Stream::register_connector */ public function test_stream_connector_registration() { $initial_classes = array( 'existing_connector' ); @@ -123,7 +123,7 @@ public function test_stream_connector_registration() { } $this->assertNotNull( $activitypub_connector, 'ActivityPub connector should be registered when Stream plugin is available' ); - $this->assertInstanceOf( 'Activitypub\Integration\Stream_Connector', $activitypub_connector ); + $this->assertInstanceOf( 'Activitypub\Integration\Stream\Connector', $activitypub_connector ); } else { // When Stream plugin is not available, the filter should return unchanged classes. $result = apply_filters( 'wp_stream_connectors', $initial_classes ); @@ -277,7 +277,7 @@ public function test_callback_activitypub_handled_follow() { // Capture the log call. $logged_data = null; - $stream_connector = $this->createPartialMock( Stream_Connector::class, array( 'log' ) ); + $stream_connector = $this->createPartialMock( Connector::class, array( 'log' ) ); $stream_connector->expects( $this->once() ) ->method( 'log' ) ->willReturnCallback( @@ -324,7 +324,7 @@ public function test_callback_activitypub_handled_follow_with_error() { // Capture the log call. $logged_data = null; - $stream_connector = $this->createPartialMock( Stream_Connector::class, array( 'log' ) ); + $stream_connector = $this->createPartialMock( Connector::class, array( 'log' ) ); $stream_connector->expects( $this->once() ) ->method( 'log' ) ->willReturnCallback( @@ -364,7 +364,7 @@ public function test_callback_activitypub_outbox_processing_complete() { // Capture the log call. $logged_data = null; - $stream_connector = $this->createPartialMock( Stream_Connector::class, array( 'log' ) ); + $stream_connector = $this->createPartialMock( Connector::class, array( 'log' ) ); $stream_connector->expects( $this->once() ) ->method( 'log' ) ->willReturnCallback( @@ -420,7 +420,7 @@ public function test_callback_activitypub_outbox_processing_batch_complete() { // Capture the log call. $logged_data = null; - $stream_connector = $this->createPartialMock( Stream_Connector::class, array( 'log' ) ); + $stream_connector = $this->createPartialMock( Connector::class, array( 'log' ) ); $stream_connector->expects( $this->once() ) ->method( 'log' ) ->willReturnCallback( @@ -475,7 +475,7 @@ public function test_prepare_outbox_data_for_response( $post_title, $expected_da 'post_title' => $post_title, ); - $reflection = new \ReflectionClass( Stream_Connector::class ); + $reflection = new \ReflectionClass( Connector::class ); $method = $reflection->getMethod( 'prepare_outbox_data_for_response' ); $method->setAccessible( true ); @@ -534,7 +534,7 @@ public function test_prepare_outbox_data_for_response_post_url() { 'post_title' => $post_url, ); - $reflection = new \ReflectionClass( Stream_Connector::class ); + $reflection = new \ReflectionClass( Connector::class ); $method = $reflection->getMethod( 'prepare_outbox_data_for_response' ); $method->setAccessible( true ); @@ -566,7 +566,7 @@ public function test_prepare_outbox_data_for_response_comment_url() { 'post_title' => $comment_url, ); - $reflection = new \ReflectionClass( Stream_Connector::class ); + $reflection = new \ReflectionClass( Connector::class ); $method = $reflection->getMethod( 'prepare_outbox_data_for_response' ); $method->setAccessible( true ); @@ -622,7 +622,7 @@ public function test_prepare_outbox_data_for_response_author_url() { 'post_title' => $author_url, ); - $reflection = new \ReflectionClass( Stream_Connector::class ); + $reflection = new \ReflectionClass( Connector::class ); $method = $reflection->getMethod( 'prepare_outbox_data_for_response' ); $method->setAccessible( true ); @@ -661,7 +661,7 @@ public function test_prepare_outbox_data_for_response_blog_user_url() { 'post_title' => $blog_user_url, ); - $reflection = new \ReflectionClass( Stream_Connector::class ); + $reflection = new \ReflectionClass( Connector::class ); $method = $reflection->getMethod( 'prepare_outbox_data_for_response' ); $method->setAccessible( true ); From a9b5d24437eec8ccd1b79873ed1b7d902526425b Mon Sep 17 00:00:00 2001 From: Automattic Bot Date: Tue, 28 Oct 2025 18:17:25 +0100 Subject: [PATCH 2/4] Add changelog --- .github/changelog/2383-from-description | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 .github/changelog/2383-from-description diff --git a/.github/changelog/2383-from-description b/.github/changelog/2383-from-description new file mode 100644 index 0000000000..aa07e16b45 --- /dev/null +++ b/.github/changelog/2383-from-description @@ -0,0 +1,4 @@ +Significance: patch +Type: changed + +Reorganize integration loader and move Stream integration into dedicated folder structure. From f11766891ffb11e29d5c511cc58ac95987abba46 Mon Sep 17 00:00:00 2001 From: Konstantin Obenland Date: Tue, 28 Oct 2025 12:25:25 -0500 Subject: [PATCH 3/4] Fix BuddyPress hook registration timing Move BuddyPress hook registration outside of plugin_init() to ensure it's registered before bp_include fires. BuddyPress fires bp_include on plugins_loaded:8, so registering it in plugin_init() (which runs at plugins_loaded:10) would be too late. --- integration/load.php | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) diff --git a/integration/load.php b/integration/load.php index af17d6fd0a..90c18f14af 100644 --- a/integration/load.php +++ b/integration/load.php @@ -26,16 +26,6 @@ function plugin_init() { Akismet::init(); } - /** - * Adds BuddyPress support. - * - * This class handles the compatibility with BuddyPress. - * Hooks into bp_include to ensure BuddyPress is fully loaded. - * - * @see https://buddypress.org/ - */ - \add_action( 'bp_include', array( __NAMESPACE__ . '\Buddypress', 'init' ), 0 ); - /** * Adds Classic Editor support. * @@ -205,3 +195,12 @@ function ( $transformer, $data, $object_class ) { // Register activation and deactivation hooks for LiteSpeed Cache integration. \register_activation_hook( ACTIVITYPUB_PLUGIN_FILE, array( __NAMESPACE__ . '\LiteSpeed_Cache', 'add_htaccess_rules' ) ); \register_deactivation_hook( ACTIVITYPUB_PLUGIN_FILE, array( __NAMESPACE__ . '\LiteSpeed_Cache', 'remove_htaccess_rules' ) ); + +/** + * Load the BuddyPress integration. + * + * Only load code that needs BuddyPress to run once BP is loaded and initialized. + * + * @see https://buddypress.org/ + */ +\add_action( 'bp_include', array( __NAMESPACE__ . '\Buddypress', 'init' ), 0 ); From c711265811445ae4c353a6d832df9123e730b0b9 Mon Sep 17 00:00:00 2001 From: Automattic Bot Date: Thu, 30 Oct 2025 10:46:17 +0000 Subject: [PATCH 4/4] Prettify --- package-lock.json | 63 ++++++++++++++++++++++++++++++++++++----------- 1 file changed, 49 insertions(+), 14 deletions(-) diff --git a/package-lock.json b/package-lock.json index 50e2b659af..1fb208cb38 100644 --- a/package-lock.json +++ b/package-lock.json @@ -122,6 +122,7 @@ "integrity": "sha512-yJ474Zv3cwiSOO9nXJuqzvwEeM+chDuQ8GJirw+pZ91sCGCyOZ3dJkVE09fTV0VEVzXyLWhh3G/AolYTPX7Mow==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "@ampproject/remapping": "^2.2.0", "@babel/code-frame": "^7.25.7", @@ -2098,6 +2099,7 @@ "integrity": "sha512-h0Un1ieD+HUrzBH6dJXhod3ifSghk5Hw/2Y4/KHBziPlZecrFyE9YOTPU6eOs0V9pYl8gOs86fkr/KN8lUX39A==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "@keyv/serialize": "^1.1.1" } @@ -2138,6 +2140,7 @@ } ], "license": "MIT", + "peer": true, "engines": { "node": ">=18" }, @@ -2161,6 +2164,7 @@ } ], "license": "MIT", + "peer": true, "engines": { "node": ">=18" } @@ -2295,6 +2299,7 @@ "integrity": "sha512-O000MLDBDdk/EohJPFUqvnp4qnHeYkVP5B0xEG0D/L7cOKP9kefu2DXn8dj74cQfsEzUqh+sr1RzFqiL1o+PpA==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "@babel/runtime": "^7.18.3", "@emotion/babel-plugin": "^11.13.5", @@ -4050,6 +4055,7 @@ "integrity": "sha512-3giAOQvZiH5F9bMlMiv8+GSPMeqg0dbaeo58/0SlA9sxSqZhnUtxzX9/2FzyhS9sWQf5S0GJE0AKBrFqjpeYcg==", "dev": true, "license": "Apache-2.0", + "peer": true, "engines": { "node": ">=8.0.0" } @@ -4073,6 +4079,7 @@ "integrity": "sha512-s5vvxXPVdjqS3kTLKMeBMvop9hbWkwzBpu+mUO2M7sZtlkyDJGwFe33wRKnbaYDo8ExRVBIIdwIGrqpxHuKttA==", "dev": true, "license": "Apache-2.0", + "peer": true, "engines": { "node": ">=14" }, @@ -4086,6 +4093,7 @@ "integrity": "sha512-OOCM2C/QIURhJMuKaekP3TRBxBKxG/TWWA0TL2J6nXUtDnuCtccy49LUJF8xPFXMX+0LMcxFpCo8M9cGY1W6rQ==", "dev": true, "license": "Apache-2.0", + "peer": true, "dependencies": { "@opentelemetry/semantic-conventions": "1.28.0" }, @@ -4568,6 +4576,7 @@ "integrity": "sha512-5UxZqiAgLYGFjS4s9qm5mBVo433u+dSPUFWVWXmLAD4wB65oMCoXaJP1KJa9DIYYMeHu3z4BZcStG3LC593cWA==", "dev": true, "license": "Apache-2.0", + "peer": true, "dependencies": { "@opentelemetry/core": "1.30.1", "@opentelemetry/semantic-conventions": "1.28.0" @@ -4595,6 +4604,7 @@ "integrity": "sha512-jVPgBbH1gCy2Lb7X0AVQ8XAfgg0pJ4nvl8/IiQA6nxOsPvS+0zMJaFSs2ltXe0J6C8dqjcnpyqINDJmU30+uOg==", "dev": true, "license": "Apache-2.0", + "peer": true, "dependencies": { "@opentelemetry/core": "1.30.1", "@opentelemetry/resources": "1.30.1", @@ -4623,6 +4633,7 @@ "integrity": "sha512-JD6DerIKdJGmRp4jQyX5FlrQjA4tjOw1cvfsPAZXfOOEErMUHjPcPSICS+6WnM0nB0efSFARh0KAZss+bvExOA==", "dev": true, "license": "Apache-2.0", + "peer": true, "engines": { "node": ">=14" } @@ -4994,6 +5005,7 @@ "integrity": "sha512-vSMYtL/zOcFpvJCW71Q/OEGQb7KYBPAdKh35WNSkaZA75JlAO8ED8UN6GUNTm3drWomcbcqRPFqQbLae8yBTdg==", "dev": true, "license": "Apache-2.0", + "peer": true, "dependencies": { "playwright": "1.56.1" }, @@ -5941,6 +5953,7 @@ "integrity": "sha512-8QqtOQT5ACVlmsvKOJNEaWmRPmcojMOzCz4Hs2BGG/toAp/K38LcsMRyLp349glq5AzJbCEeimEoxaX6v/fLrA==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "@babel/core": "^7.21.3", "@svgr/babel-preset": "8.1.0", @@ -6193,8 +6206,7 @@ "resolved": "https://registry.npmjs.org/@types/aria-query/-/aria-query-5.0.4.tgz", "integrity": "sha512-rfT93uj5s0PRL7EzccGMs3brplhcrghnDoV26NqKhCAS1hVo+WdNsPvE/yb6ilfr5hi2MEk6d5EWJTKdxg8jVw==", "dev": true, - "license": "MIT", - "peer": true + "license": "MIT" }, "node_modules/@types/babel__core": { "version": "7.20.5", @@ -6302,6 +6314,7 @@ "integrity": "sha512-FXx2pKgId/WyYo2jXw63kk7/+TY7u7AziEJxJAnSFzHlqTAS3Ync6SvgYAN/k4/PQpnnVuzoMuVnByKK2qp0ag==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "@types/estree": "*", "@types/json-schema": "*" @@ -6648,6 +6661,7 @@ "integrity": "sha512-RFA/bURkcKzx/X9oumPG9Vp3D3JUgus/d0b67KB0t5S/raciymilkOa66olh78MUI92QLbEJevO7rvqU/kjwKA==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "@types/prop-types": "*", "csstype": "^3.0.2" @@ -6659,6 +6673,7 @@ "integrity": "sha512-MEe3UeoENYVFXzoXEWsvcpg6ZvlrFNlOQ7EOsvhI3CfAXwzPfO8Qwuxd40nepsYKqyyVQnTdEfv68q91yLcKrQ==", "dev": true, "license": "MIT", + "peer": true, "peerDependencies": { "@types/react": "^18.0.0" } @@ -6874,6 +6889,7 @@ "integrity": "sha512-tbsV1jPne5CkFQCgPBcDOt30ItF7aJoZL997JSF7MhGQqOeT3svWRYxiqlfA5RUdlHN6Fi+EI9bxqbdyAUZjYQ==", "dev": true, "license": "BSD-2-Clause", + "peer": true, "dependencies": { "@typescript-eslint/scope-manager": "6.21.0", "@typescript-eslint/types": "6.21.0", @@ -8269,6 +8285,7 @@ "integrity": "sha512-wPfA0BGnfyMLsiOhkxac2eNXTmcHH5r8nEnfSxf2bDQWRUcbQ2Laae53N0NplGmI79wsBSOXRfMCibM+gyq2rg==", "dev": true, "license": "GPL-2.0-or-later", + "peer": true, "dependencies": { "@inquirer/prompts": "^7.2.0", "chalk": "^4.0.0", @@ -9309,6 +9326,7 @@ "integrity": "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==", "dev": true, "license": "MIT", + "peer": true, "bin": { "acorn": "bin/acorn" }, @@ -9402,6 +9420,7 @@ "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "fast-deep-equal": "^3.1.1", "fast-json-stable-stringify": "^2.0.0", @@ -9619,7 +9638,6 @@ "integrity": "sha512-b0P0sZPKtyu8HkeRAfCq0IfURZK+SuwMjY1UXGBU27wpAiTwQAIlq56IbIO+ytk/JjS1fMR14ee5WBBfKi5J6A==", "dev": true, "license": "Apache-2.0", - "peer": true, "dependencies": { "dequal": "^2.0.3" } @@ -10464,6 +10482,7 @@ } ], "license": "MIT", + "peer": true, "dependencies": { "baseline-browser-mapping": "^2.8.9", "caniuse-lite": "^1.0.30001746", @@ -12261,7 +12280,6 @@ "integrity": "sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==", "dev": true, "license": "MIT", - "peer": true, "engines": { "node": ">=6" } @@ -12320,7 +12338,8 @@ "resolved": "https://registry.npmjs.org/devtools-protocol/-/devtools-protocol-0.0.1507524.tgz", "integrity": "sha512-OjaNE7qpk6GRTXtqQjAE5bGx6+c4F1zZH0YXtpZQLM92HNXx4zMAaqlKhP4T52DosG6hDW8gPMNhGOF8xbwk/w==", "dev": true, - "license": "BSD-3-Clause" + "license": "BSD-3-Clause", + "peer": true }, "node_modules/diff": { "version": "4.0.2", @@ -12399,8 +12418,7 @@ "resolved": "https://registry.npmjs.org/dom-accessibility-api/-/dom-accessibility-api-0.5.16.tgz", "integrity": "sha512-X7BJ2yElsnOJ30pZF4uIIDfBEVgF4XEBxL9Bxhy6dnrm5hkzqmsWHGTiHqRiITNhMyFLyAiWndIJP7Z1NTteDg==", "dev": true, - "license": "MIT", - "peer": true + "license": "MIT" }, "node_modules/dom-serializer": { "version": "2.0.0", @@ -12983,6 +13001,7 @@ "deprecated": "This version is no longer supported. Please see https://eslint.org/version-support for other options.", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "@eslint-community/eslint-utils": "^4.2.0", "@eslint-community/regexpp": "^4.6.1", @@ -13039,6 +13058,7 @@ "integrity": "sha512-/IGJ6+Dka158JnP5n5YFMOszjDWrXggGz1LaK/guZq9vZTmniaKlHcsscvkAhn9y4U+BU3JuUdYvtAMcv30y4A==", "dev": true, "license": "MIT", + "peer": true, "bin": { "eslint-config-prettier": "bin/cli.js" }, @@ -16732,6 +16752,7 @@ "integrity": "sha512-NIy3oAFp9shda19hy4HK0HRTWKtPJmGdnvywu01nOqNC2vZg+Z+fvJDxpMQA88eb2I9EcafcdjYgsDthnYTvGw==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "@jest/core": "^29.7.0", "@jest/types": "^29.6.3", @@ -18432,7 +18453,8 @@ "resolved": "https://registry.npmjs.org/devtools-protocol/-/devtools-protocol-0.0.1508733.tgz", "integrity": "sha512-QJ1R5gtck6nDcdM+nlsaJXcelPEI7ZxSMw1ujHpO1c4+9l+Nue5qlebi9xO1Z2MGr92bFOQTW7/rrheh5hHxDg==", "dev": true, - "license": "BSD-3-Clause" + "license": "BSD-3-Clause", + "peer": true }, "node_modules/lighthouse/node_modules/puppeteer-core/node_modules/ws": { "version": "8.18.3", @@ -18722,7 +18744,6 @@ "integrity": "sha512-h5bgJWpxJNswbU7qCrV0tIKQCaS3blPDrqKWx+QxzuzL1zGUzij9XCWLrSLsJPu5t+eWA/ycetzYAO5IOMcWAQ==", "dev": true, "license": "MIT", - "peer": true, "bin": { "lz-string": "bin/bin.js" } @@ -19616,6 +19637,7 @@ "integrity": "sha512-cuXAJJB1Rdqz0UO6w524matlBqDBjcNt7Ru+RDIu4y6RI1gVqiWBnylrK8sPRk81gGBA0X8hJbDXolVOoTc+sA==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "ajv": "^6.12.6", "ajv-errors": "^1.0.1", @@ -20771,6 +20793,7 @@ } ], "license": "MIT", + "peer": true, "dependencies": { "nanoid": "^3.3.11", "picocolors": "^1.1.1", @@ -21547,6 +21570,7 @@ "integrity": "sha512-5SYSgFKSyhCbk6SrXyMpqjb5+MQBgfvEKE/OC+PujcY34sOpqtr+0AZQtPYx5IA6VxynQ7rUPCtKzyovpj9Bpg==", "dev": true, "license": "MIT", + "peer": true, "funding": { "type": "opencollective", "url": "https://opencollective.com/preact" @@ -21569,6 +21593,7 @@ "integrity": "sha512-X4UlrxDTH8oom9qXlcjnydsjAOD2BmB6yFmvS4Z2zdTzqqpRWb+fbqrH412+l+OUXmbzJlSXjlMFYPgYG12IAA==", "dev": true, "license": "MIT", + "peer": true, "bin": { "prettier": "bin/prettier.cjs" }, @@ -21598,7 +21623,6 @@ "integrity": "sha512-Qb1gy5OrP5+zDf2Bvnzdl3jsTf1qXVMazbvCoKhtKqVs4/YK4ozX4gKQJJVyNe+cajNPn0KoC0MC3FUmaHWEmQ==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "ansi-regex": "^5.0.1", "ansi-styles": "^5.0.0", @@ -21614,7 +21638,6 @@ "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", "dev": true, "license": "MIT", - "peer": true, "engines": { "node": ">=10" }, @@ -21627,8 +21650,7 @@ "resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz", "integrity": "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==", "dev": true, - "license": "MIT", - "peer": true + "license": "MIT" }, "node_modules/process-nextick-args": { "version": "2.0.1", @@ -21991,6 +22013,7 @@ "integrity": "sha512-wS+hAgJShR0KhEvPJArfuPVN1+Hz1t0Y6n5jLrGQbkb4urgPE/0Rve+1kMB1v/oWgHgm4WIcV+i7F2pTVj+2iQ==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "loose-envify": "^1.1.0" }, @@ -22064,6 +22087,7 @@ "integrity": "sha512-5m4nQKp+rZRb09LNH59GM4BxTh9251/ylbKIbpe7TpGxfJ+9kv6BLkLBXIjjspbgbnIBNqlI23tRnTWT0snUIw==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "loose-envify": "^1.1.0", "scheduler": "^0.23.2" @@ -22100,6 +22124,7 @@ "integrity": "sha512-jCvmsr+1IUSMUyzOkRcvnVbX3ZYC6g9TDrDbFuFmRDq7PD4yaGbLKNQL6k2jnArV8hjYxh7hVhAZB6s9HDGpZA==", "dev": true, "license": "MIT", + "peer": true, "engines": { "node": ">=0.10.0" } @@ -22339,7 +22364,8 @@ "resolved": "https://registry.npmjs.org/redux/-/redux-5.0.1.tgz", "integrity": "sha512-M9/ELqF6fy8FwmkpnF0S3YKOqMyoWJ4+CS5Efg2ct3oY9daQvd/Pc71FpGZsVsbl3Cpb+IIcjBDUnnyBdQbq4w==", "dev": true, - "license": "MIT" + "license": "MIT", + "peer": true }, "node_modules/reflect.getprototypeof": { "version": "1.0.10", @@ -22922,6 +22948,7 @@ "integrity": "sha512-t+YPtOQHpGW1QWsh1CHQ5cPIr9lbbGZLZnbihP/D/qZj/yuV68m8qarcV17nvkOX81BCrvzAlq2klCQFZghyTg==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "chokidar": "^4.0.0", "immutable": "^5.0.2", @@ -23027,6 +23054,7 @@ "integrity": "sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "fast-deep-equal": "^3.1.3", "fast-uri": "^3.0.1", @@ -24563,6 +24591,7 @@ } ], "license": "MIT", + "peer": true, "dependencies": { "@csstools/css-parser-algorithms": "^3.0.5", "@csstools/css-tokenizer": "^3.0.4", @@ -24898,6 +24927,7 @@ "integrity": "sha512-8sLjZwK0R+JlxlYcTuVnyT2v+htpdrjDOKuMcOVdYjt52Lh8hWRYpxBPoKx/Zg+bcjc3wx6fmQevMmUztS/ccA==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "cssesc": "^3.0.0", "util-deprecate": "^1.0.2" @@ -25673,6 +25703,7 @@ "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", "dev": true, "license": "(MIT OR CC0-1.0)", + "peer": true, "engines": { "node": ">=10" }, @@ -26320,6 +26351,7 @@ "integrity": "sha512-7h/weGm9d/ywQ6qzJ+Xy+r9n/3qgp/thalBbpOi5i223dPXKi04IBtqPN9nTd+jBc7QKfvDbaBnFipYp4sJAUQ==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "@types/eslint-scope": "^3.7.7", "@types/estree": "^1.0.8", @@ -26428,6 +26460,7 @@ "integrity": "sha512-pIDJHIEI9LR0yxHXQ+Qh95k2EvXpWzZ5l+d+jIo+RdSm9MiHfzazIxwwni/p7+x4eJZuvG1AJwgC4TNQ7NRgsg==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "@discoveryjs/json-ext": "^0.5.0", "@webpack-cli/configtest": "^2.1.1", @@ -26508,6 +26541,7 @@ "integrity": "sha512-0XavAZbNJ5sDrCbkpWL8mia0o5WPOd2YGtxrEiZkBK9FjLppIUK2TgxK6qGD2P3hUXTJNNPVibrerKcx5WkR1g==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "@types/bonjour": "^3.5.9", "@types/connect-history-api-fallback": "^1.3.5", @@ -27194,6 +27228,7 @@ "integrity": "sha512-OIDwaflOaq4wC6YlPBy2L6ceKeKuF7DeTxx+jPzv1FHn9tCZ0ZwSRnUBxD05E3yed46fv/FWJbvR+Ud7x0L7zw==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "lib0": "^0.2.99" },