diff --git a/.remarkrc.json b/.remarkrc.json new file mode 100644 index 00000000..417653c2 --- /dev/null +++ b/.remarkrc.json @@ -0,0 +1,10 @@ +{ + "plugins": [ + "remark-frontmatter", + "remark-gfm", + "remark-preset-lint-recommended" + ], + "settings": { + "linkReference": false + } +} \ No newline at end of file diff --git a/docs/README.md b/docs/README.md index e2adf9a0..09f078bc 100644 --- a/docs/README.md +++ b/docs/README.md @@ -5,12 +5,12 @@ | Title | Description | |------------------------------------|------------------------------| -| [GET vs POST](explanation/get-vs-post.md) | Explanation on choosing between GET and POST methods for WPGraphQL requests. | -| [GraphQL Endpoints](explanation/graphql-endpoints.md) | Documentation on differences between using /graphql or ?graphql for WPGraphQL endpoint. | -| [Headless Authentication](explanation/headless-authentication.md) | Overview of user authentication and access control in a decoupled WordPress architecture. | -| [Rendering Options](explanation/rendering-options.md) | A document that explores the various approaches to rendering content from a headless WordPress installation. | -| [Routing](explanation/routing.md) | A comprehensive explanation on routing in a headless WordPress application. | -| [Sitemaps](explanation/sitemaps.md) | A comprehensive explanation on sitemaps in a headless WordPress application. | +| [GET vs POST](explanation/get-vs-post/index.md) | Explanation on choosing between GET and POST methods for WPGraphQL requests. | +| [GraphQL Endpoints](explanation/graphql-endpoints/index.md) | Documentation on differences between using /graphql or ?graphql for WPGraphQL endpoint. | +| [Headless Authentication](explanation/headless-authentication/index.md) | Overview of user authentication and access control in a decoupled WordPress architecture. | +| [Rendering Options](explanation/rendering-options/index.md) | A document that explores the various approaches to rendering content from a headless WordPress installation. | +| [Routing](explanation/routing/index.md) | A comprehensive explanation on routing in a headless WordPress application. | +| [Sitemaps](explanation/sitemaps/index.md) | A comprehensive explanation on sitemaps in a headless WordPress application. | ## How To Documentation diff --git a/docs/explanation/get-vs-post.md b/docs/explanation/get-vs-post/index.md similarity index 93% rename from docs/explanation/get-vs-post.md rename to docs/explanation/get-vs-post/index.md index 2e6e6538..46621562 100644 --- a/docs/explanation/get-vs-post.md +++ b/docs/explanation/get-vs-post/index.md @@ -3,7 +3,7 @@ title: "GET vs POST in WPGraphQL" description: "A guide on the differences between using a GET request with a query parameter versus a POST request to the /graphql endpoint." --- -# GET vs POST in WPGraphQL +## Overview When interacting with WPGraphQL, selecting the correct HTTP method to fetch data is crucial. This guide explains the differences between using a GET request with a query parameter versus a POST request to the /graphql endpoint. @@ -52,3 +52,7 @@ curl -X POST \ # Summary While both methods have their uses, POST requests are generally recommended for WPGraphQL due to their flexibility, security advantages, and ability to handle complex queries. However, GET requests can be useful for simple, cacheable queries and is useful when paired with caching mechanisms like the Smart Cache plugin. Consider your specific use case, security requirements, and caching needs when choosing between the two methods. + +## Contributing + +If you feel like something is missing or you want to add documentation, we encourage you to contribute! Please check out our [Contributing Guide](https://github.com/wpengine/hwptoolkit/blob/main/CONTRIBUTING.md) for more details. diff --git a/docs/explanation/graphql-endpoints.md b/docs/explanation/graphql-endpoints/index.md similarity index 89% rename from docs/explanation/graphql-endpoints.md rename to docs/explanation/graphql-endpoints/index.md index 1defcea7..388b1b64 100644 --- a/docs/explanation/graphql-endpoints.md +++ b/docs/explanation/graphql-endpoints/index.md @@ -42,4 +42,8 @@ add_filter( 'graphql_endpoint', 'my_new_graphql_endpoint' ); ``` This code would change the default `/graphql` endpoint to `/my_endpoint`. -Alternatively, you can configure the endpoint directly in the **WPGraphQL Settings** under **GraphQL Endpoint**, without needing to modify your code. \ No newline at end of file +Alternatively, you can configure the endpoint directly in the **WPGraphQL Settings** under **GraphQL Endpoint**, without needing to modify your code. + +## Contributing + +If you feel like something is missing or you want to add documentation, we encourage you to contribute! Please check out our [Contributing Guide](https://github.com/wpengine/hwptoolkit/blob/main/CONTRIBUTING.md) for more details. diff --git a/docs/explanation/headless-authentication.md b/docs/explanation/headless-authentication/index.md similarity index 96% rename from docs/explanation/headless-authentication.md rename to docs/explanation/headless-authentication/index.md index 6dd404b7..d91de247 100644 --- a/docs/explanation/headless-authentication.md +++ b/docs/explanation/headless-authentication/index.md @@ -104,4 +104,8 @@ To tie everything together, we will provide: Our approach to authentication in headless WordPress emphasizes **modularity**, **security**, and developer **experience**. To support these principles, we will provide **ready-to-use code snippets** and **example boilerplate code** that you can easily integrate into your application. ## Example use case -For example, if you're building a headless WordPress application with a React frontend, you can use our code snippets to implement Credentials authentication. You can integrate our boilerplate code for handling access tokens securely, including token storage and refresh logic, without needing to install additional dependencies. \ No newline at end of file +For example, if you're building a headless WordPress application with a React frontend, you can use our code snippets to implement Credentials authentication. You can integrate our boilerplate code for handling access tokens securely, including token storage and refresh logic, without needing to install additional dependencies. + +## Contributing + +If you feel like something is missing or you want to add documentation, we encourage you to contribute! Please check out our [Contributing Guide](https://github.com/wpengine/hwptoolkit/blob/main/CONTRIBUTING.md) for more details. diff --git a/docs/explanation/rendering-options.md b/docs/explanation/rendering-options/index.md similarity index 96% rename from docs/explanation/rendering-options.md rename to docs/explanation/rendering-options/index.md index 78c14a20..d0b0600f 100644 --- a/docs/explanation/rendering-options.md +++ b/docs/explanation/rendering-options/index.md @@ -3,7 +3,6 @@ title: "Headless WordPress Rendering Options" description: "A guide that explores the various approaches to rendering content from a headless WordPress installation, their trade-offs, and best practices." --- -# Headless WordPress Rendering Options ## Introduction This document explores the various approaches to rendering content from a headless WordPress installation. As a front-end developer working with headless WordPress, you'll need to make important decisions about how to handle and display WordPress content in your frontend application. This guide aims to help you understand the available options, their trade-offs, and best practices. @@ -142,3 +141,7 @@ Considerations * Styling Parity: Achieving perfect styling parity can be challenging due to the dynamic nature of WordPress styles. * Maintenance: Styles may change with theme updates, customizations or major WordPress updates, requiring periodic updates in your headless application. + +## Contributing + +If you feel like something is missing or you want to add documentation, we encourage you to contribute! Please check out our [Contributing Guide](https://github.com/wpengine/hwptoolkit/blob/main/CONTRIBUTING.md) for more details. diff --git a/docs/explanation/routing.md b/docs/explanation/routing/index.md similarity index 99% rename from docs/explanation/routing.md rename to docs/explanation/routing/index.md index 8030c8c6..5257f649 100644 --- a/docs/explanation/routing.md +++ b/docs/explanation/routing/index.md @@ -469,3 +469,7 @@ In traditional WordPress, custom post types (CPTs) are registered using `registe - `/portfolio/` → Archive page for portfolio items - `/portfolio/project-name/` → Single portfolio item + +## Contributing + +If you feel like something is missing or you want to add documentation, we encourage you to contribute! Please check out our [Contributing Guide](https://github.com/wpengine/hwptoolkit/blob/main/CONTRIBUTING.md) for more details. diff --git a/docs/explanation/sitemaps.md b/docs/explanation/sitemaps/index.md similarity index 95% rename from docs/explanation/sitemaps.md rename to docs/explanation/sitemaps/index.md index 9f327f0c..cbe8cb1a 100644 --- a/docs/explanation/sitemaps.md +++ b/docs/explanation/sitemaps/index.md @@ -3,7 +3,7 @@ title: "Sitemaps in Headless WordPress" description: "A guide on sitemaps in headless WordPress. It explains the challenges, and the different implementation approaches for sitemap generation." --- -# Sitemaps in WordPress: A Comprehensive Overview +## A Comprehensive Overview ## What is a Sitemap? A sitemap is an XML file that provides a structured list of pages on a website by helping search engines discover and crawl content more efficiently. It acts as a roadmap of your website's structure, containing important metadata about each page. @@ -108,7 +108,7 @@ This route will serve the WordPress `sitemap.xml` in your Next.js application dy - **Cons** * Limited flexibility for custom frontend routes not defined in WordPress * Requires proper URL transformation to replace backend URLs with frontend URLs - * May require additional handling for caching and performance + * May require additional handling for caching and performance * May propagate any errors experienced in WordPress when proxying the `sitemap.xml` 2. **Generating a Sitemap from GraphQL Content** @@ -133,13 +133,13 @@ export async function generateSitemap() { fetchAllPages(), ]); const allContent = [ - ...data.posts.nodes.map(post => ({ - slug: `posts/${post.slug}`, - modified: post.modified + ...data.posts.nodes.map(post => ({ + slug: `posts/${post.slug}`, + modified: post.modified })), - ...data.pages.nodes.map(page => ({ - slug: page.slug, - modified: page.modified + ...data.pages.nodes.map(page => ({ + slug: page.slug, + modified: page.modified })), // Add custom frontend routes here { slug: '', modified: new Date().toISOString() }, // Homepage @@ -159,17 +159,17 @@ export async function generateSitemap() { } export async function getServerSideProps({ res }) { const sitemap = await generateSitemap(); - + res.setHeader('Content-Type', 'application/xml'); res.write(sitemap); res.end(); - + return { props: {} }; } export async function GET() { const sitemap = await generateSitemap(); - + return new Response(sitemap, { headers: { 'Content-Type': 'application/xml', @@ -182,7 +182,7 @@ export async function GET() { * Ability to include custom frontend routes not defined in WordPress * Easy integration with Next.js data fetching methods -- **Cons**: +- **Cons**: * More complex implementation than proxying * Requires manual updates to include new content types or custom routes * May require pagination handling for large sites @@ -199,25 +199,25 @@ import { DOMParser } from 'xmldom'; export async function GET() { const response = await fetch(`${process.env.WORDPRESS_URL}/wp-sitemap.xml`); const sitemapIndex = await response.text(); - + const parser = new DOMParser(); const xmlDoc = parser.parseFromString(sitemapIndex, 'text/xml'); const sitemapUrls = Array.from(xmlDoc.getElementsByTagName('loc')).map( node => node.textContent ); - + const processedSitemaps = await Promise.all( sitemapUrls.map(async (url) => { const sitemapResponse = await fetch(url); const sitemapContent = await sitemapResponse.text(); - + return sitemapContent.replace( new RegExp(process.env.WORDPRESS_URL, 'g'), process.env.FRONTEND_URL ); }) ); - + const frontendRoutesSitemap = ` @@ -228,7 +228,7 @@ export async function GET() { `; - + const combinedSitemap = ` @@ -242,7 +242,7 @@ export async function GET() { `; - + return new Response(combinedSitemap, { headers: { 'Content-Type': 'application/xml', @@ -261,3 +261,7 @@ export async function GET() { * Most complex implementation of the three approaches. * Requires handling multiple sitemap files * May have performance implications if not properly cached + +## Contributing + +If you feel like something is missing or you want to add documentation, we encourage you to contribute! Please check out our [Contributing Guide](https://github.com/wpengine/hwptoolkit/blob/main/CONTRIBUTING.md) for more details. diff --git a/docs/explanation/sitemaps-1.png b/docs/explanation/sitemaps/sitemaps-1.png similarity index 100% rename from docs/explanation/sitemaps-1.png rename to docs/explanation/sitemaps/sitemaps-1.png diff --git a/docs/how-to/install-toolkit-plugins/index.md b/docs/how-to/install-toolkit-plugins/index.md index 17fbfbd7..75849d38 100644 --- a/docs/how-to/install-toolkit-plugins/index.md +++ b/docs/how-to/install-toolkit-plugins/index.md @@ -3,7 +3,7 @@ title: "Installing HWP Toolkit Plugins with Composer" description: "A guide on how to install any HWP Toolkit plugin using Composer, which is the recommended way for modern WordPress development workflows." --- -# Installing HWP Toolkit Plugins with Composer +## Overview You can install any HWP Toolkit plugin using Composer, which is the recommended way for modern WordPress development workflows. @@ -15,6 +15,9 @@ You can also install them manually from our [Releases](https://github.com/wpengi - WordPress 6.0+ - PHP 7.4+ +>[!NOTE] +> WPGraphQL Logging Plugin requires PHP 8.1.2 in order to work. + ### Available Plugins - [wpengine/hwp-previews](https://github.com/wpengine/hwptoolkit/tree/main/plugins/hwp-previews#readme) diff --git a/docs/how-to/nextjs-pages-router/enable-apq/index.md b/docs/how-to/nextjs-pages-router/enable-apq/index.md index 92977474..a76df42d 100644 --- a/docs/how-to/nextjs-pages-router/enable-apq/index.md +++ b/docs/how-to/nextjs-pages-router/enable-apq/index.md @@ -125,3 +125,7 @@ const client = new ApolloClient({ On the Network tab you should see your query being sent as a GET request. ![Network tab of browser is open, showing the GraphQL query being sent as GET.](./images/gql-pq-get.png) + +## Contributing + +If you feel like something is missing or you want to add documentation, we encourage you to contribute! Please check out our [Contributing Guide](https://github.com/wpengine/hwptoolkit/blob/main/CONTRIBUTING.md) for more details. diff --git a/docs/index.md b/docs/index.md index 8ea9b807..9b798ced 100644 --- a/docs/index.md +++ b/docs/index.md @@ -3,9 +3,6 @@ title: "Introduction" description: "Introduction to the Headless WordPress Toolkit, a modern, framework-agnostic collection of plugins and packages for building headless WordPress applications." --- - -# Introduction - ## What is the Headless WordPress Toolkit? The Headless WordPress Toolkit is a modern, framework-agnostic toolkit for building headless WordPress applications. It provides a collection of plugins, packages, and examples to help developers make WordPress a better headless CMS. @@ -18,10 +15,10 @@ The toolkit includes several WordPress plugins to enhance the headless experienc | Plugin | Description | |--------|-------------| -| [`hwp-previews`](../plugins/hwp-previews/) | Headless Previews solution for WordPress: fully configurable preview URLs via the settings page which is framework agnostic. | -| [`wpgraphql-webhooks`](../plugins/wpgraphql-webhooks/) | Extends WPGraphQL to support webhook subscriptions and dispatching for headless WordPress environments. | -| [`wpgraphql-logging`](../plugins/wpgraphql-logging/) | Logging for WPGraphQL requests with granular lifecycle events and Monolog integration. | -| [`wpgraphql-debug-extensions`](../plugins/wpgraphql-debug-extensions/) | Advanced debugging, performance analysis, and metric collection for WPGraphQL. | +| [hwp-previews](../plugins/hwp-previews/) | Headless Previews solution for WordPress: fully configurable preview URLs via the settings page which is framework agnostic. | +| [wpgraphql-webhooks](../plugins/wpgraphql-webhooks/) | Extends WPGraphQL to support webhook subscriptions and dispatching for headless WordPress environments. | +| [wpgraphql-logging](../plugins/wpgraphql-logging/) | Logging for WPGraphQL requests with granular lifecycle events and Monolog integration. | +| [wpgraphql-debug-extensions](../plugins/wpgraphql-debug-extensions/) | Advanced debugging, performance analysis, and metric collection for WPGraphQL. | You can find more information about installation in the [plugins documentation](../plugins/README.md). @@ -29,7 +26,7 @@ You can find more information about installation in the [plugins documentation]( We provide NPM packages that can be used in your frontend applications. All packages use vanilla ES Modules with no build step. -- [`@wpengine/hwp-toolbar`](../packages/toolbar/) — in active development (not yet published) +- [@wpengine/hwp-toolbar](../packages/toolbar/) — in active development (not yet published) > [!NOTE] > No packages are published to npm yet. These are pre-release and subject to change. @@ -41,3 +38,7 @@ This project contains a wide variety of examples demonstrating how to use the He Most examples include a `wp-env` setup, allowing you to fully configure a headless application with a single command. For a full list of examples and how to run them, please see the [examples documentation](../examples/README.md). + +## Contributing + +If you feel like something is missing or you want to add documentation, we encourage you to contribute! Please check out our [Contributing Guide](https://github.com/wpengine/hwptoolkit/blob/main/CONTRIBUTING.md) for more details. diff --git a/docs/nav.json b/docs/nav.json index 13476c53..5dc6754a 100644 --- a/docs/nav.json +++ b/docs/nav.json @@ -9,33 +9,27 @@ "children": [ { "title": "GET vs POST", - "route": "/toolkit/explanation/get-vs-post/", - "append": ".md" + "route": "/toolkit/explanation/get-vs-post/" }, { "title": "GraphQL Endpoints", - "route": "/toolkit/explanation/graphql-endpoints/", - "append": ".md" + "route": "/toolkit/explanation/graphql-endpoints/" }, { "title": "Headless Authentication", - "route": "/toolkit/explanation/headless-authentication/", - "append": ".md" + "route": "/toolkit/explanation/headless-authentication/" }, { "title": "Rendering Options", - "route": "/toolkit/explanation/rendering-options/", - "append": ".md" + "route": "/toolkit/explanation/rendering-options/" }, { "title": "Routing", - "route": "/toolkit/explanation/routing/", - "append": ".md" + "route": "/toolkit/explanation/routing/" }, { "title": "Sitemaps", - "route": "/toolkit/explanation/sitemaps/", - "append": ".md" + "route": "/toolkit/explanation/sitemaps/" } ] }, @@ -52,5 +46,53 @@ "route": "/toolkit/how-to/nextjs-pages-router/enable-apq/" } ] + }, + { + "title": "WPGraphQL Logging Plugin", + "route": "/toolkit/plugins/wpgraphql-logging/", + "children": [ + { + "title": "How to Guides", + "route": "/toolkit/plugins/wpgraphql-logging/how-to/", + "children": [ + { + "title": "Add a new Handler", + "route": "/toolkit/plugins/wpgraphql-logging/how-to/logger-add-handler/" + }, + { + "title": "Add a new Processor", + "route": "/toolkit/plugins/wpgraphql-logging/how-to/logger-add-processor/" + }, + { + "title": "Add or Remove a Rule", + "route": "/toolkit/plugins/wpgraphql-logging/how-to/logger-add-remove-rules/" + }, + { + "title": "Update the Log Store Service", + "route": "/toolkit/plugins/wpgraphql-logging/how-to/update-log-store-service/" + }, + { + "title": "Use the Events Pub/Sub System", + "route": "/toolkit/plugins/wpgraphql-logging/how-to/event-pub-sub/" + }, + { + "title": "Add Data to an Event", + "route": "/toolkit/plugins/wpgraphql-logging/how-to/event-add-context/" + }, + { + "title": "Add a new Settings Field", + "route": "/toolkit/plugins/wpgraphql-logging/how-to/admin-add-fields/" + }, + { + "title": "Add a new Settings Tab", + "route": "/toolkit/plugins/wpgraphql-logging/how-to/admin-add-new-tab/" + }, + { + "title": "Update the Admin Grid", + "route": "/toolkit/plugins/wpgraphql-logging/how-to/admin-add-view-column/" + } + ] + } + ] } ] \ No newline at end of file diff --git a/plugins/wpgraphql-logging/docs/.gitkeep b/docs/plugins/wpgraphql-logging/.gitkeep similarity index 100% rename from plugins/wpgraphql-logging/docs/.gitkeep rename to docs/plugins/wpgraphql-logging/.gitkeep diff --git a/docs/plugins/wpgraphql-logging/how-to/admin-add-fields/index.md b/docs/plugins/wpgraphql-logging/how-to/admin-add-fields/index.md new file mode 100644 index 00000000..5a23bd33 --- /dev/null +++ b/docs/plugins/wpgraphql-logging/how-to/admin-add-fields/index.md @@ -0,0 +1,118 @@ +--- +title: "How To Guide: Add a new Settings Field" +description: "Learn how to add custom settings fields to the WPGraphQL Logging plugin admin interface and retrieve their values programmatically." +--- + +## Overview + +In this guide, you will learn how to extend the WPGraphQL Logging plugin's admin interface by adding custom settings fields and integrating them with the logging system. + +We will demonstrate how to create a new checkbox field in the admin settings, retrieve its value programmatically, and use it to control logging behavior through custom rules. This approach is useful for adding application-specific configuration options, creating conditional logging scenarios, or providing users with granular control over what gets logged in their GraphQL operations. + +## Step 1 - Add Settings Field + +Add a field to an existing tab using the provided filters. Common tabs are `basic_configuration` and `data_management`. + + +```php +get_option_key(); +$option_values = $configuration->get_option_value('log_only_get_pages_query'); + +``` + +## Step 2: Implement Custom Rule + +Using the Rule Manager, we will add a custom rule to see if this is checked, and if so make sure the query contains `GetPages`. + +First, let's create the rule. This class will implement the `LoggingRuleInterface` and contain the logic to check our custom setting. + +```php +get_extra()['memory_peak_usage']`. +Each row item should implement the interface `\WPGraphQL\Logging\Logger\Api\LogEntityInterface` which has the method `get_extra`. We will use this to fetch the memory data and parse the data. + ```php add_filter( 'wpgraphql_logging_logs_table_column_value', function( $value, $item, $column_name ) { @@ -41,7 +40,7 @@ add_filter( 'wpgraphql_logging_logs_table_column_value', function( $value, $item return $value; } - if ( ! $item instanceof \WPGraphQL\Logging\Logger\Database\WordPressDatabaseEntity ) { + if ( ! $item instanceof \WPGraphQL\Logging\Logger\Api\LogEntityInterface ) { return $value; } @@ -61,3 +60,13 @@ add_filter( 'wpgraphql_logging_logs_table_column_value', function( $value, $item return esc_html( (string) $raw ); }, 10, 3 ); ``` + +We should now be able to see the peak memory usage in the admin grid under GraphQL Logs -> All Logs. + +![Add New Column to Logs Table](screenshot.png) +*Example of a custom Memory Peak Usage column added to the WPGraphQL Logging admin table* + + +## Contributing + +We welcome and appreciate contributions from the community. If you'd like to help improve this documentation, please check out our [Contributing Guide](https://github.com/wpengine/hwptoolkit/blob/main/CONTRIBUTING.md) for more details on how to get started. diff --git a/docs/plugins/wpgraphql-logging/how-to/admin-add-view-column/screenshot.png b/docs/plugins/wpgraphql-logging/how-to/admin-add-view-column/screenshot.png new file mode 100644 index 00000000..228cb397 Binary files /dev/null and b/docs/plugins/wpgraphql-logging/how-to/admin-add-view-column/screenshot.png differ diff --git a/docs/plugins/wpgraphql-logging/how-to/event-add-context/index.md b/docs/plugins/wpgraphql-logging/how-to/event-add-context/index.md new file mode 100644 index 00000000..b75bc666 --- /dev/null +++ b/docs/plugins/wpgraphql-logging/how-to/event-add-context/index.md @@ -0,0 +1,50 @@ +--- +title: "How To Guide: Add Data to an Event" +description: "Learn how to add custom context data to WPGraphQL Logging event." +--- + +## Overview + +In this guide, you will learn how to extend the logging capabilities of WPGraphQL Logging by transforming events and adding custom context data. + +We will demonstrate how to modify event payloads before they are logged, which can be useful for adding application-specific metadata, changing log levels dynamically, or enriching log entries with additional debugging information that helps with monitoring and troubleshooting your GraphQL operations. + +## Example: Add Context Data to an Event + +Use the `WPGraphQL\Logging\Plugin::transform()` helper to mutate the event payload before it is logged and emitted. + +```php + [ + 'myField' => [ + 'type' => 'String', + 'description' => __( 'A field for my mutation.', 'my-textdomain' ), + ], + ], + 'outputFields' => [ + 'success' => [ + 'type' => 'Boolean', + 'description' => __( 'Whether or not the mutation was successful.', 'my-textdomain' ), + ], + ], + 'resolve' => function( $root, $args, $context, $info ) { + // Do mutation logic... + $result = ['success' => true]; + + // Emit a custom event + Plugin::emit( 'my_plugin/my_custom_mutation_resolved', [ + 'context' => [ + 'input' => $args['input'], + 'result' => $result + ], + ] ); + + return $result; + } +] ); +``` + +## Contributing + +We welcome and appreciate contributions from the community. If you'd like to help improve this documentation, please check out our [Contributing Guide](https://github.com/wpengine/hwptoolkit/blob/main/CONTRIBUTING.md) for more details on how to get started. diff --git a/docs/plugins/wpgraphql-logging/how-to/event-pub-sub/screenshot.png b/docs/plugins/wpgraphql-logging/how-to/event-pub-sub/screenshot.png new file mode 100644 index 00000000..5a3d7759 Binary files /dev/null and b/docs/plugins/wpgraphql-logging/how-to/event-pub-sub/screenshot.png differ diff --git a/docs/plugins/wpgraphql-logging/how-to/index.md b/docs/plugins/wpgraphql-logging/how-to/index.md new file mode 100644 index 00000000..194121d3 --- /dev/null +++ b/docs/plugins/wpgraphql-logging/how-to/index.md @@ -0,0 +1,27 @@ +--- +title: "How-to Guides" +description: "Step-by-step guides for implementing specific features and achieving practical goals with the WPGraphQL Logging plugin." +--- + +I see you found the root of the How-to guides! How-to guides are a place where we walk you through implementing specific features of the WPGraphQL Logging plugin. + +## Available How-to Guides + +| Guide | Description | +| ------------------------------------------------------------------ | -------------------------------------------------------------------- | +| [Add a New Handler](logger-add-handler/index.md) | Integrate custom Monolog handlers for different logging destinations | +| [Add a New Processor](logger-add-processor/index.md) | Create custom processors to modify log records | +| [Add or Remove a Rule](logger-add-remove-rules/index.md) | Define custom rules for when and what to log | +| [Update the Log Store Service](update-log-store-service/index.md) | Customize the log storage service implementation | +| [Use the Events Pub/Sub system](event-pub-sub/index.md) | Learn how to create and publish custom events in the logging system | +| [Add Data to an Event](event-add-context/index.md) | Add additional context data to existing events | +| [Add a new Settings Field](admin-add-fields/index.md) | Add custom fields to the plugin settings page | +| [Add a new Settings Tab](admin-add-new-tab/index.md) | Create additional tabs in the admin interface | +| [Update the Admin Grid](admin-add-view-column/index.md) | Customize the admin log viewing interface | + +> \[!note] Learn More +> For more info on how we layout our documentation and the the role played by How-to guides, please read about the [*Diátaxis*](https://diataxis.fr/how-to-guides/) approach we use. + +## Contributing + +If you feel like something is missing or you want to add documentation, we encourage you to contribute! Please check out our [Contributing Guide](https://github.com/wpengine/hwptoolkit/blob/main/CONTRIBUTING.md) for more details. diff --git a/docs/plugins/wpgraphql-logging/how-to/logger-add-handler/index.md b/docs/plugins/wpgraphql-logging/how-to/logger-add-handler/index.md new file mode 100644 index 00000000..a11f359d --- /dev/null +++ b/docs/plugins/wpgraphql-logging/how-to/logger-add-handler/index.md @@ -0,0 +1,73 @@ +--- +title: "How To Guide: Add a new Handler" +description: "This guide shows how to log to a file using a Monolog handler, either in addition to the default WordPress database handler or as a replacement. It also covers per-instance overrides." +--- + +## Overview + +In this guide, you will learn how to extend the logging capabilities of WPGraphQL Logging by adding a new [Monolog](https://github.com/Seldaek/monolog) handler. Specifically, we will demonstrate how to send logs to a file, which can be useful for long-term storage, offline analysis, or integration with external log management systems. + +## What is a Monolog Handler? + +Handlers decide where logs are written. By default, WPGraphQL Logging uses a custom `WordPressDatabaseHandler` to store logs in the database. You can add more destinations (files, streams, third-party services) or replace the defaults. + +> \[!NOTE] +> See [Monolog documentation](https://seldaek.github.io/monolog/doc/02-handlers-formatters-processors.html) for a list of handlers and processors + +## Example 1: Add a new Monolog Handler + +In this example, we will add a new Monolog `StreamHandler` to write to file for any logs which are deemed as errors but keep the existing default handler. + +```php + \[!NOTE] +> You could also use the [RotatingFileHandler](https://github.com/Seldaek/monolog/blob/main/src/Monolog/Handler/RotatingFileHandler.php) and implement `$maxFiles` to delete older files. + +## Example 2: Replace the default database handler + +In this example, we will replace the default database handler with the new Monolog handler. + +```php + \[!TIP] +> You should restrict public access to the log file if being written in a public directory + +* Ensure the logs directory is writable by the web server user. +* Consider `Monolog\\Handler\\RotatingFileHandler` to rotate files by day and limit disk usage. +* You can combine multiple handlers (e.g., database + file + Slack) either globally (filter) or per instance. + +## Contributing + +We welcome and appreciate contributions from the community. If you'd like to help improve this documentation, please check out our [Contributing Guide](https://github.com/wpengine/hwptoolkit/blob/main/CONTRIBUTING.md) for more details on how to get started. diff --git a/docs/plugins/wpgraphql-logging/how-to/logger-add-processor/index.md b/docs/plugins/wpgraphql-logging/how-to/logger-add-processor/index.md new file mode 100644 index 00000000..bfa77def --- /dev/null +++ b/docs/plugins/wpgraphql-logging/how-to/logger-add-processor/index.md @@ -0,0 +1,62 @@ +--- +title: "How To Guide: Add a new Processor" +description: "Learn how to add custom Monolog processors to the WPGraphQL Logging plugin to transform log records." +--- + +## Overview + + +In this guide, you will learn how to extend the logging capabilities of WPGraphQL Logging by adding a new [Monolog](https://github.com/Seldaek/monolog) processor. + +Specifically, we will demonstrate how to add the current WordPress environment variable to the extra data, which can be useful for distinguishing between development, staging, and production environments in your logs. + +### What is a Monolog Processor? + +Processors in Monolog add or transform data on each log record before handlers write it. They can modify the `context` or `extra` arrays on a record. See [Monolog documentation](https://seldaek.github.io/monolog/doc/02-handlers-formatters-processors.html). + +### Step 1: Create a new Monolog Processor class + +Create a PHP class that implements `Monolog\Processor\ProcessorInterface` and returns the updated `LogRecord`. + +```php +extra['environment'] = wp_get_environment_type(); + return $record; + } +} +``` + +### Step 2: Register the processor globally + +Use the `wpgraphql_logging_default_processors` filter to add your processor to all logger instances. + +```php +[!NOTE] +> The `LoggerService` allows you to specify your own list of default handlers and processors if you ever prefer to re-use it or change the list of default handlers and processors e.g. + +```php +LoggerService::get_instance($channel, $handlers, $processors, $default_context); +``` + + +## Contributing + +We welcome and appreciate contributions from the community. If you'd like to help improve this documentation, please check out our [Contributing Guide](https://github.com/wpengine/hwptoolkit/blob/main/CONTRIBUTING.md) for more details on how to get started. diff --git a/docs/plugins/wpgraphql-logging/how-to/logger-add-processor/screenshot.png b/docs/plugins/wpgraphql-logging/how-to/logger-add-processor/screenshot.png new file mode 100644 index 00000000..6b215168 Binary files /dev/null and b/docs/plugins/wpgraphql-logging/how-to/logger-add-processor/screenshot.png differ diff --git a/docs/plugins/wpgraphql-logging/how-to/logger-add-remove-rules/index.md b/docs/plugins/wpgraphql-logging/how-to/logger-add-remove-rules/index.md new file mode 100644 index 00000000..6bf31479 --- /dev/null +++ b/docs/plugins/wpgraphql-logging/how-to/logger-add-remove-rules/index.md @@ -0,0 +1,130 @@ +--- +title: "How To Guide: Add or Remove a Rule" +description: "Learn how to create and register custom logging rules with the WPGraphQL Logging plugin." +--- + +## Overview + +This guide shows how to create a custom logging rule that only passes when the GraphQL query contains a specific substring (like "GetPost"), how to register it with the RuleManager, and how to remove existing rules. + +### Architecture + +When logging an event through a filter or action it will first check if an event should be logged using the [`RuleManager`](https://github.com/wpengine/hwptoolkit/blob/main/plugins/wpgraphql-logging/src/Logger/Rules/RuleManager.php). + +All rules must implement the interface Rules implement [`WPGraphQL\Logging\Logger\Rules\LoggingRuleInterface`](https://github.com/wpengine/hwptoolkit/blob/main/plugins/wpgraphql-logging/src/Logger/Api/LoggingRuleInterface.php) + +This contains 2 required methods + +- `passes( array $config, ?string $query_string ): bool` +- `get_name(): string` + +>[!NOTE] +>The name must be unique. Additionally when logging an event, the list of rules registered in the RuleManager will be checked to see if they have all passed. + + +## Option 1: Add a new rule + +Firstly create a class that implements the interface and returns true only if the query contains a given substring. + +```php + fail + } + return stripos( $query_string, $this->needle ) !== false; + } + + public function get_name(): string { + // Ensure unique name per rule; adjust if you need multiple variants + return 'contains_string_rule'; + } +} +``` + +We then need to register the rule with the RuleManager. Use the `wpgraphql_logging_rule_manager` filter to add your rule. This runs when the logger helper initializes rules. + +```php + $rule ) { + if ( $rule instanceof EnabledRule ) { + unset( $rules[ $i ] ); + } + } + return array_values( $rules ); +} ); +``` + +The result should be if you have unchecked "Enabled" under Basic Configuration, the event should be logged providing it passes other rules. + +## Screenshots + +### Enabled Setting - Disabled + +![Configuration showing the Enabled checkbox disabled](screenshots/admin-settings.png) + +### Query + +![Example of a query being executed](screenshots/query.png) + +### Admin Logs View + +![Admin interface showing logged queries](screenshots/admin-view.png) + +The query was logged even with the enabled checkbox unchecked as we removed the default rule. + +## Contributing + +We welcome and appreciate contributions from the community. If you'd like to help improve this documentation, please check out our [Contributing Guide](https://github.com/wpengine/hwptoolkit/blob/main/CONTRIBUTING.md) for more details on how to get started. diff --git a/docs/plugins/wpgraphql-logging/how-to/logger-add-remove-rules/screenshots/admin-settings.png b/docs/plugins/wpgraphql-logging/how-to/logger-add-remove-rules/screenshots/admin-settings.png new file mode 100644 index 00000000..4625bb9f Binary files /dev/null and b/docs/plugins/wpgraphql-logging/how-to/logger-add-remove-rules/screenshots/admin-settings.png differ diff --git a/docs/plugins/wpgraphql-logging/how-to/logger-add-remove-rules/screenshots/admin-view.png b/docs/plugins/wpgraphql-logging/how-to/logger-add-remove-rules/screenshots/admin-view.png new file mode 100644 index 00000000..444f207c Binary files /dev/null and b/docs/plugins/wpgraphql-logging/how-to/logger-add-remove-rules/screenshots/admin-view.png differ diff --git a/docs/plugins/wpgraphql-logging/how-to/logger-add-remove-rules/screenshots/query.png b/docs/plugins/wpgraphql-logging/how-to/logger-add-remove-rules/screenshots/query.png new file mode 100644 index 00000000..50fc232d Binary files /dev/null and b/docs/plugins/wpgraphql-logging/how-to/logger-add-remove-rules/screenshots/query.png differ diff --git a/plugins/wpgraphql-logging/docs/how-to/logger_replace_log_store_service.md b/docs/plugins/wpgraphql-logging/how-to/update-log-store-service/index.md similarity index 84% rename from plugins/wpgraphql-logging/docs/how-to/logger_replace_log_store_service.md rename to docs/plugins/wpgraphql-logging/how-to/update-log-store-service/index.md index 74a3dd9b..7265461e 100644 --- a/plugins/wpgraphql-logging/docs/how-to/logger_replace_log_store_service.md +++ b/docs/plugins/wpgraphql-logging/how-to/update-log-store-service/index.md @@ -1,4 +1,9 @@ -# How to Replace the Log Storage Service +--- +title: "How To Guide: Update the Log Store Service" +description: "Learn how to replace the default database logging with a custom log storage implementation in the WPGraphQL Logging plugin." +--- + +## Overview The WPGraphQL Logging plugin provides a robust database logging solution out of the box. However, for advanced use cases or integration with external logging systems, you can replace the default storage mechanism with your own custom implementation. @@ -18,7 +23,6 @@ First, create a class that implements `LogServiceInterface`. This is a simplifie ```php Settings. + +By default the following settings are pre-configured. + +### Basic Configuration + +| Setting | Default Value | Description | +| --------------- | ---------------------- | ---------------------------------------------------- | +| Enabled | true | Master switch to enable/disable logging | +| Exclude Queries | `__schema,GetSeedNode` | To exclude introspection and Faust Seed Node queries | +| Data Sampling | 10% | Log only 10% of the queries | +| Log Points | Selects all | Which lifecycle events to log | + +### Data Management + +| Setting | Default Value | Description | +| ----------------------------- | ------------- | ------------------------------------- | +| Data Deletion Enabled | true | Enable automatic log cleanup | +| Number of Days to Retain Logs | 7 | How long to keep logs before deletion | +| Data Sanitization Enabled | true | Enable data sanitization | +| Data Sanitization Method | Recommended | Which sanitization rules to apply | + +### Basic Configuration + +![Basic Configuration](screenshots/admin_configuration_basic.png) + +* **Enabled**: The master switch to turn logging on or off. +* **IP Restrictions**: A comma-separated list of IPv4/IPv6 addresses. When set, only requests originating from these IPs will be logged. +* **Exclude Queries**: A comma-separated list of GraphQL query or mutation names to be excluded from logging. +* **Data Sampling Rate**: A dropdown to select the percentage of requests that will be logged. +* **Log Points**: A multi-select field to choose the specific WPGraphQL lifecycle events for which data should be logged. +* **Log Response**: A toggle to determine whether the GraphQL response body should be included in the log. + +### Data Management + +![Data Management](screenshots/admin_configuration_data_management.png) + +* **Data Deletion Enabled**: Enable data deletion daily via the WP-Cron schedule. +* **Number of Days to Retain Logs**: Number of days logged should be stored. +* **Data Sanitization Enabled**: Enable data sanitization. +* **Data Sanitization Method**: Choose between two sanitization methods (default is recommended) + * **Recommended Rules (Default)**: The following fields will be removed from the event data. + * `request.app_context.viewer.data` + * `request.app_context.viewer.allcaps` + * `request.app_context.viewer.cap_key` + * `request.app_context.viewer.caps` + * `variables.username` + * `variables.password` + * `variables.email` + * **Custom Rules**: Define your own sanitization rules by specifying fields to anonymize, remove, or truncate. + +## Viewing Logs + +Once setup, you can view logs under GraphQL Logs -> All Logs. The admin screen is a custom implementation of the WordPress `WP_List_Table` class and provides several powerful features for managing your logs. + +![Admin View](screenshots/admin_view.png) + +### Downloading Logs + +You can download individual logs in CSV format. + +**Example** + +```csv +ID,Date,Level,"Level Name",Message,Channel,Query,Context,Extra +5293,"2025-10-06 15:41:34",200,INFO,"WPGraphQL Response",wpgraphql_logging,"{ posts(first: 10) ...""memory_peak_usage"":""18 MB""}" +``` + +### Filtering Logs + +You can also filter logs with the following filters: + +1. Level +2. Start Date +3. End Date + +> \[!NOTE] +> Indexes have been added to the level and datetime column for the database handler to help improve performance. + +![Admin View with Filters](screenshots/admin_view_filters.png) + +### Bulk Actions + +You can delete selected logs or all logs using the bulk action controls. + +## Uninstallation + +By default, WPGraphQL Logging preserves all logged data when the plugin is deactivated to prevent accidental data loss. + +If you would like to remove all logged data, you must set the PHP constant before you uninstall the plugin: + +```php +define( 'WP_GRAPHQL_LOGGING_UNINSTALL_PLUGIN', true ); +``` + +> \[!WARNING] +> **Data Loss Warning**: When `WP_GRAPHQL_LOGGING_UNINSTALL_PLUGIN` is defined as `true`, deactivating the plugin will permanently delete all logged data and drop the plugin's database tables. This action is irreversible. + +## How to Guides + +### 🛠️ Logging + +* [Add a New Handler](how-to/logger-add-handler/index.md) +* [Add a New Processor](how-to/logger-add-processor/index.md) +* [Add or Remove a Rule](how-to/logger-add-remove-rules/index.md) +* [Update the Log Store Service](how-to/update-log-store-service/index.md) + +### ♻️ Events + +* [Use the Events Pub/Sub system](how-to/event-pub-sub/index.md) +* [Add Data to an Event](how-to/event-add-context/index.md) + +### 📈 Admin + +* [Add a new Settings Field](how-to/admin-add-fields/index.md) +* [Add a new Settings Tab](how-to/add-add-new-tab/index.md) +* [Update the Admin Grid](how-to/admin_add_view_column.md) + + +## Contributing + +If you feel like something is missing or you want to add documentation, we encourage you to contribute! Please check out our [Contributing Guide](https://github.com/wpengine/hwptoolkit/blob/main/CONTRIBUTING.md) for more details. diff --git a/package.json b/package.json index d89ab1de..bb051e72 100644 --- a/package.json +++ b/package.json @@ -21,7 +21,8 @@ "dev": "bash ./scripts/dev.sh", "stop": "pnpm --filter '*' stop", "release": "npm run build && changeset publish", - "changeset": "changeset" + "changeset": "changeset", + "reformat:md": "remark --rc-path .remarkrc.json --output --" }, "engines": { "node": ">=18", @@ -39,7 +40,13 @@ "@wordpress/env": "^10.34.0", "@wordpress/jest-console": "^8.31.0", "@wordpress/scripts": "30.24.0", + "remark-gfm": "^4.0.1", "rimraf": "^5.0.5" }, - "packageManager": "pnpm@10.20.0" + "packageManager": "pnpm@10.20.0", + "dependencies": { + "remark-cli": "^12.0.1", + "remark-frontmatter": "^5.0.0", + "remark-preset-lint-recommended": "^7.0.1" + } } diff --git a/plugins/README.md b/plugins/README.md index 9de9bb30..617b1f4a 100644 --- a/plugins/README.md +++ b/plugins/README.md @@ -6,10 +6,10 @@ WordPress plugins for the Headless WordPress Toolkit. Each plugin is paired with | Plugin | Description | |--------|-------------| -| [`hwp-previews`](./hwp-previews/README.md) | Headless Previews solution for WordPress: fully configurable preview URLs via the settings page which is framework agnostic. | -| [`wpgraphql-webhooks`](./wpgraphql-webhooks/README.md) | Extends WPGraphQL to support webhook subscriptions and dispatching for headless WordPress environments. | -| [`wpgraphql-logging`](./wpgraphql-logging/README.md) | Logging for WPGraphQL requests with granular lifecycle events and Monolog integration. | -| [`wpgraphql-debug-extensions`](./wpgraphql-debug-extensions/README.md) | Advanced debugging, performance analysis, and metric collection for WPGraphQL. | +| [hwp-previews](./hwp-previews/README.md) | Headless Previews solution for WordPress: fully configurable preview URLs via the settings page which is framework agnostic. | +| [wpgraphql-webhooks](./wpgraphql-webhooks/README.md) | Extends WPGraphQL to support webhook subscriptions and dispatching for headless WordPress environments. | +| [wpgraphql-logging](./wpgraphql-logging/README.md) | Logging for WPGraphQL requests with granular lifecycle events and Monolog integration. | +| [wpgraphql-debug-extensions](./wpgraphql-debug-extensions/README.md) | Advanced debugging, performance analysis, and metric collection for WPGraphQL. | ## Install diff --git a/plugins/wpgraphql-logging/README.md b/plugins/wpgraphql-logging/README.md index 6dedd132..e46f0b41 100644 --- a/plugins/wpgraphql-logging/README.md +++ b/plugins/wpgraphql-logging/README.md @@ -1,6 +1,6 @@ # WPGraphQL Logging -A WPGraphQL logging plugin that provides visibility into request lifecycle to help quickly identify and resolve bottlenecks in your headless WordPress application. +A logging plugin that provides visibility into request lifecycle to help quickly identify and resolve bottlenecks in your headless WordPress application. ----- @@ -23,7 +23,7 @@ A WPGraphQL logging plugin that provides visibility into request lifecycle to he ## Overview -WPGraphQL Logging is a plugin that integrates directly with the WPGraphQL Query Lifecycle, capturing detailed information about each GraphQL request. +WPGraphQL Logging plugin provides observability and visibility into the GraphQL request and event lifecycle. This capability gives users the understandability needed to quickly identify and resolve performance issues and bottlenecks within their headless WordPress application. ### Key Features * **Granular Control**: Choose which events in the request lifecycle to log, giving you precise control over the data you capture. @@ -31,7 +31,7 @@ WPGraphQL Logging is a plugin that integrates directly with the WPGraphQL Query * **Flexible Log Handling**: Leverages the powerful Monolog logging library, enabling developers to add custom processors and handlers to route logs to various destinations like Slack, files, or external services. >[!IMPORTANT] ->For detailed developer guides and examples, see our [How-To Guides](https://github.com/wpengine/hwptoolkit/blob/main/plugins/wpgraphql-logging/docs/index.md#how-to-guides). +>For detailed developer guides and examples, see our [How-To Guides](https://github.com/wpengine/hwptoolkit/blob/main/docs/plugins/wpgraphql-logging/index.md#how-to-guides). --- @@ -60,7 +60,7 @@ Once installed and configured, the plugin should begin to log uncached WPGraphQL ## Documentation -For detailed usage instructions, developer references, and examples, please visit the [Documentation](https://github.com/wpengine/hwptoolkit/blob/main/plugins/wpgraphql-logging/docs/index.md) folder included with this plugin. +For detailed usage instructions, developer references, and examples, please visit the [Documentation](https://github.com/wpengine/hwptoolkit/blob/main/docs/plugins/wpgraphql-logging/index.md) folder included with this plugin. ## License diff --git a/plugins/wpgraphql-logging/docs/how-to/admin_add_fields.md b/plugins/wpgraphql-logging/docs/how-to/admin_add_fields.md deleted file mode 100644 index bc98d7c6..00000000 --- a/plugins/wpgraphql-logging/docs/how-to/admin_add_fields.md +++ /dev/null @@ -1,66 +0,0 @@ -## How to add a new field to an existing tab and query it - -This guide shows how to add custom fields to the WPGraphQL Logging settings and how to read or query those values. - -![WPGraphQL Logging Settings Page](../screenshots/admin_how_to_add_field.png) -*The WPGraphQL Logging settings page with Basic Configuration and Data Management tabs where custom fields can be added* - - -### Step 1 — Add a field via filter - -Add a field to an existing tab using the provided filters. Common tabs are `basic_configuration` and `data_management`. - -Example: add a checkbox to Basic Configuration - -```php -add_filter( 'wpgraphql_logging_basic_configuration_fields', function( $fields ) { - $fields['my_feature_enabled'] = new \WPGraphQL\Logging\Admin\Settings\Fields\Field\CheckboxField( - 'my_feature_enabled', - 'basic_configuration', - __( 'Enable My Feature', 'my-plugin' ) - ); - return $fields; -}); -``` - -Example: add a text input to Data Management - -```php -add_filter( 'wpgraphql_logging_data_management_fields', function( $fields ) { - $fields['my_data_region'] = new \WPGraphQL\Logging\Admin\Settings\Fields\Field\TextInputField( - 'my_data_region', - 'data_management', - __( 'Data Region', 'my-plugin' ), - '', - __( 'e.g., us-east-1', 'my-plugin' ), - __( 'us-east-1', 'my-plugin' ) - ); - return $fields; -}); -``` - -Notes: - -- Field classes available: `CheckboxField`, `TextInputField`, `SelectField`, `TextIntegerField`. -- The second argument is the tab key (use the tab’s `get_name()`), not the option key. - -### Step 2 — Where the value is stored - -Values are saved to the option key `wpgraphql_logging_settings` under the tab key and field id, for example: - -```php -$options = get_option( 'wpgraphql_logging_settings', [] ); -// Example structure -// [ -// 'basic_configuration' => [ 'my_feature_enabled' => true ], -// 'data_management' => [ 'my_data_region' => 'us-east-1' ], -// ] -``` - -### Step 3 — Read the value in PHP - -```php -$options = get_option( 'wpgraphql_logging_settings', [] ); -$is_enabled = ! empty( $options['basic_configuration']['my_feature_enabled'] ); -$my_data_region = $options['data_management']['my_data_region'] ?? ''; -``` diff --git a/plugins/wpgraphql-logging/docs/how-to/events_add_context.md b/plugins/wpgraphql-logging/docs/how-to/events_add_context.md deleted file mode 100644 index 11cfc6f3..00000000 --- a/plugins/wpgraphql-logging/docs/how-to/events_add_context.md +++ /dev/null @@ -1,79 +0,0 @@ -## How to add context data to a logged WPGraphQL event - -This guide shows two supported ways to inject custom context data into events that WPGraphQL Logging records: - -- Programmatic transform API (recommended for plugins/themes using PHP namespaces) -- WordPress filter API (easy to drop into any project) - -Refer to the [Events Reference](../reference/events.md) for the list of available event names. - - -![Adding custom context data to WPGraphQL events](../screenshots/event_add_context_data.png) -*Example of custom context data being added to a WPGraphQL event log entry* - - -### Option A — Programmatic transform API - -Use the `WPGraphQL\Logging\Plugin::transform()` helper to mutate the event payload before it is logged and emitted. - -```php - $_SERVER['REMOTE_ADDR'] ?? null, - 'agent' => $_SERVER['HTTP_USER_AGENT'] ?? null, - ]; - return $payload; -}, 10, 1 ); -``` diff --git a/plugins/wpgraphql-logging/docs/how-to/events_pub_sub.md b/plugins/wpgraphql-logging/docs/how-to/events_pub_sub.md deleted file mode 100644 index 83e6c4ed..00000000 --- a/plugins/wpgraphql-logging/docs/how-to/events_pub_sub.md +++ /dev/null @@ -1,130 +0,0 @@ -## How to use the WPGraphQL Logging events pub/sub system - -The plugin exposes a lightweight pub/sub bus around key WPGraphQL lifecycle events and bridges them to standard WordPress actions/filters. You can: - -- Subscribe (read-only) to observe event payloads -- Transform payloads before core code logs and emits them -- Publish your own custom events for your app/plugins - -See the [Events Reference](../reference/events.md) for available built-in events and their mappings. - - -### Core concepts - -- Subscribe (read-only): `Plugin::on( $event, callable $listener, $priority )` -- Transform (mutate): `Plugin::transform( $event, callable $transform, $priority )` -- Emit (publish): `Plugin::emit( $event, array $payload )` - -Priorities run ascending (lower numbers first). Transforms must return the updated payload array; subscribers receive the payload and do not return. - - -### Programmatic API (recommended) - -```php - [ 'user_id' => (int) $user_id ], - ] ); -} ); -``` - -Notes: - -- Built-in events are transformed internally before they are logged and then published. -- `emit()` publishes to subscribers and the WordPress action bridge; it does not apply transforms by itself. - - If you want the “transform then publish” pattern for your custom event, call `EventManager::transform( $event, $payload )` yourself before publishing. - - -### WordPress bridge (actions and filters) - -For each event, the system also fires a WordPress action and applies a WordPress filter so you can interact without the PHP helpers. - -- Action: `wpgraphql_logging_event_{event_name}` (fires after subscribers run) -- Filter: `wpgraphql_logging_filter_{event_name}` (used when core transforms a payload) - -Examples: - -```php - $level, - 'level_name' => $level_name, - 'query' => $context['query'] ?? '', - 'context' => $context, - 'message' => 'Test' - ] ); -}, 10); - -``` - ->[!NOTE] -> You can also add a custom handler if you want to log data to that service via the LoggerService. - - - -### Troubleshooting - -- If your transform isn’t taking effect, ensure you’re targeting the correct event and that your callable returns the modified array. -- If you only call `emit()`, transforms won’t run automatically; they only run where core calls `transform()`. -- Use priorities to control ordering with other plugins (`5` runs before `10`). diff --git a/plugins/wpgraphql-logging/docs/how-to/logger_add_new_handler.md b/plugins/wpgraphql-logging/docs/how-to/logger_add_new_handler.md deleted file mode 100644 index c3e08a18..00000000 --- a/plugins/wpgraphql-logging/docs/how-to/logger_add_new_handler.md +++ /dev/null @@ -1,89 +0,0 @@ -## How to Add a New Handler (File Logging) - -This guide shows how to log to a file using a Monolog handler, either in addition to the default WordPress database handler or as a replacement. It also covers per-instance overrides. - -### What is a Handler? - -Handlers decide where logs are written. By default, WPGraphQL Logging uses a custom `WordPressDatabaseHandler` to store logs in the database. You can add more destinations (files, streams, third-party services) or replace the defaults. - ->[!NOTE] -> See for a list of handlers and processors - -### Option A: Add a file handler globally (in addition to the default) - -Use the `wpgraphql_logging_default_handlers` filter to push a `StreamHandler` that writes to a file. The default database handler will remain enabled. - -```php -info( 'Per-instance handlers configured' ); - -// Or replace defaults for the instance (file only) -$fileOnly = LoggerService::get_instance( 'file_only', [ - new StreamHandler( WP_CONTENT_DIR . '/logs/wpgraphql-file-only.log', Level::Warning ), -] ); -$fileOnly->warning( 'This goes only to the file' ); -``` - -### Tips - -- Ensure the logs directory is writable by the web server user. -- Consider `Monolog\\Handler\\RotatingFileHandler` to rotate files by day and limit disk usage. -- You can combine multiple handlers (e.g., database + file + Slack) either globally (filter) or per instance. - -### Related - -- See the [Logger reference](../reference/logging.md#filter-wpgraphql_logging_default_handlers) for `wpgraphql_logging_default_handlers` and other hooks. diff --git a/plugins/wpgraphql-logging/docs/how-to/logger_add_new_processor.md b/plugins/wpgraphql-logging/docs/how-to/logger_add_new_processor.md deleted file mode 100644 index 9078bbae..00000000 --- a/plugins/wpgraphql-logging/docs/how-to/logger_add_new_processor.md +++ /dev/null @@ -1,57 +0,0 @@ -## How to Add a New Processor - -This guide shows how to create and register a custom processor that logs the current WordPress environment (e.g. `production`, `staging`, `development`). - -### What is a Processor? - -Processors in Monolog add or transform data on each log record before handlers write it. They can modify the `context` or `extra` arrays on a record. - -### Step 1: Create a processor class - -Create a PHP class that implements `Monolog\Processor\ProcessorInterface` and returns the updated `LogRecord`. - -```php -extra['environment'] = wp_get_environment_type(); - return $record; - } -} -``` - -### Step 2: Register the processor globally - -Use the `wpgraphql_logging_default_processors` filter to add your processor to all logger instances. - -```php -info( 'Environment test' ); -``` - - -You should see `environment` in the log record's `extra` data (e.g. in the Logs admin UI or your chosen handler output). - -### Related - -- See the [Logger reference](../reference/logging.md#filter-wpgraphql_logging_default_processors) for hooks you can use to customize processors: `wpgraphql_logging_default_processors`. diff --git a/plugins/wpgraphql-logging/docs/how-to/logger_add_new_rule.md b/plugins/wpgraphql-logging/docs/how-to/logger_add_new_rule.md deleted file mode 100644 index a21588be..00000000 --- a/plugins/wpgraphql-logging/docs/how-to/logger_add_new_rule.md +++ /dev/null @@ -1,60 +0,0 @@ -## How to Add a New Rule (Query must contain string) - -This guide shows how to create a custom logging rule that only passes when the GraphQL query contains a specific substring, and how to register it with the RuleManager. - -### What is a Rule? - -Rules implement `WPGraphQL\Logging\Logger\Rules\LoggingRuleInterface` and are evaluated by the `RuleManager`. All rules must pass for logging to proceed. - -Interface reference (methods): -- `passes( array $config, ?string $query_string ): bool` -- `get_name(): string` - -### Step 1: Create the rule class - -Create a class that implements the interface and returns true only if the query contains a given substring. - -```php - fail - } - return stripos( $query_string, $this->needle ) !== false; - } - - public function get_name(): string { - // Ensure unique name per rule; adjust if you need multiple variants - return 'contains_string_rule'; - } -} -``` - -### Step 2: Register the rule with the RuleManager - -Use the `wpgraphql_logging_rule_manager` filter to add your rule. This runs when the logger helper initializes rules. - -```php -add_rule( new \MyPlugin\Logging\Rules\ContainsStringRule( 'GetPost' ) ); - return $rule_manager; -}); -``` - -### Step 3: Verify - -- GraphQL requests whose query string contains `GetPost` will be logged (assuming other rules also pass). -- Requests without that substring will be skipped by this rule, causing `is_enabled` to be false. - -### Related - -- See the [Logger reference](../reference/logging.md#filter-wpgraphql_logging_rule_manager) for the `wpgraphql_logging_rule_manager` filter. diff --git a/plugins/wpgraphql-logging/docs/how-to/run_tests.md b/plugins/wpgraphql-logging/docs/how-to/run_tests.md deleted file mode 100644 index e68969f1..00000000 --- a/plugins/wpgraphql-logging/docs/how-to/run_tests.md +++ /dev/null @@ -1,282 +0,0 @@ -# Testing WPGraphQL Logging - -## Table of Contents - -- [Overview](#overview) - - [Directory Structure](#directory-structure) - - [Technologies](#technologies) -- [Usage](#usage) - - [Running Tests](#running-tests) - - [GitHub Actions](#github-actions) -- [Setup Tests Locally](#setup-tests-locally) - - [Prerequisites](#prerequisites) - - [Docker Setup](#docker-setup) - - [What the Setup Script Does](#what-the-setup-script-does) - - [Running Tests Locally](#running-tests-locally) -- [Troubleshooting](#troubleshooting) -- [Contributing](#contributing) - ---- - -## Overview - -HWP Previews comes with automated tests for unit, integration, and acceptance (E2E) scenarios to ensure code quality and functionality. - -### Directory Structure - -A list of related files and directories for testing: - -```text -bin/ -├── install-test-env.sh # Set up test WP environment -├── run-codeception.sh # Run Codeception tests -├── run-e2e.sh # Run E2E (Playwright) tests -├── run-coverage.sh # Generate coverage reports -└── local/ - ├── setup-docker-env.sh # Setup Docker environment - ├── run-unit-tests.sh # Run unit tests in Docker with Codeception - ├── run-e2e-tests.sh # Run e2e tests in Docker with Playwright - ├── run-qa.sh # Run php code quality checks with PHPStan, Psalm and PHPCS - ├── run-wpunit.sh # Run WPUnit tests in Docker - └── run-functional.sh # Run functional tests in Docker - -tests/ -├── _data/ # Test data (e.g. DB dumps) -├── _envs/ # Environment configs -├── _output/ # Test output (logs, coverage) -├── _support/ # Helper classes, modules -├── e2e/ # End-to-end tests (Playwright) -│ ├── specs/ # Test specifications -│ │ ├── basic-usage.spec.js -│ │ ├── data-cleanup.spec.js -│ │ └── exclude-and-sanitize.spec.js -│ ├── plugins/ # Test helper plugins -│ ├── config/ # E2E test configuration -│ ├── utils.js # Helper functions -│ ├── constants.js # Test constants -│ └── playwright.config.js # Playwright configuration -├── wpunit/ # WPUnit (WordPress-aware unit/integration) test cases -├── wpunit.suite.dist.yml -└── wpunit/ - └── bootstrap.php # Bootstrap for WPUnit tests - -.env.dist # Example environment variables for testing -codeception.dist.yml # Main Codeception config -``` - -### Technologies - -We use the following technologies to run our tests: - -- [Codeception](https://codeception.com/) - PHP testing framework -- [WPBrowser](https://wpbrowser.wptestkit.dev/) - WordPress-specific testing tools -- [WPUnit](https://github.com/lipemat/wp-unit) - WordPress unit testing -- [Docker](https://www.docker.com/) - Containerized testing environment -- [Composer](https://getcomposer.org/) - PHP dependency management -- [Playwright](https://playwright.dev/) - End-to-end testing framework -- [npm](https://www.npmjs.com/) - JavaScript package manager - ---- - -## Usage - -The plugin includes the following test suites: - -1. **WP Unit Tests** – Unit and Integration Tests -2. **E2E Tests** – Acceptance tests using Playwright - -### Running Tests - -| Command | Description | -|------------------------------------------|----------------------------------------------------------| -| `composer run test:unit:coverage` | Run WPUnit (unit/integration) tests with coverage report | -| `composer run test:unit:coverage-html` | Generate an HTML code coverage report | -| `composer run test:e2e` | Run end-to-end (E2E) acceptance tests | -| `composer run test` | Run all available test suites | - -### GitHub Actions - -Automated testing runs on every pull request via GitHub Actions for a modified plugin: - -| Workflow | Description | Status | -|-------------------------|---------------------------------------------|--------| -| **Code Quality** | Runs static analysis and linting checks | [View Workflow](../../actions/workflows/code-quality.yml) | -| **E2E Tests** | Runs Playwright end-to-end acceptance tests | [View Workflow](../../actions/workflows/e2e.yml) | -| **Codeception (WPUnit)** | Runs unit and integration tests | [View Workflow](../../actions/workflows/codeception.yml) | - - -## E2E Tests - -End-to-end tests use Playwright to simulate real user workflows from configuring the plugin to viewing logs and managing data. - -### Test Suites - -| Test Suite | Description | Key Scenarios | -| -------------------------------- | -------------------------------- | -------------------------------------------------------- | -| **basic-usage.spec.js** | Core logging functionality | Enable logging, execute queries, view logs, download CSV | -| **exclude-and-sanitize.spec.js** | Query filtering and data privacy | Exclude queries, sanitize sensitive data | -| **data-cleanup.spec.js** | Data management | Configure automatic log deletion, verify cron job | - -### Test Helper Plugins - -Located in `tests/e2e/plugins/`: - -- **`reset-wpgraphql-logging-settings`** - Resets plugin settings and clears logs table for clean test state - -### Running E2E Tests - -```shell -# Start wp-env (make sure Docker is running) -npm run wp-env start - -# Run all E2E tests -npm run test:e2e - -# Run specific test file -npm run test:e2e tests/e2e/specs/basic-usage.spec.js - -# Run tests in headed mode (with browser UI) -npm run test:e2e:debug -``` - ->[!IMPORTANT] -> Test coverage for WP Unit Tests is **95%**. Any new code will require tests to be added in order to pass CI checks. This is set in [text](codeception.dist.yml) in the parameter `min_coverage`. - ---- - -## Setup Tests Locally - -### Prerequisites - -- Docker and Docker Compose installed and running -- Composer installed -- Node.js and npm installed (for E2E tests) -- Terminal/command line access - -### Docker Setup - ->[!NOTE] -> You need Docker running locally before setting up tests. Alternatively, you can copy `.env.dist` to `.env` and update the database details to point to your local database. However, this will make database changes, so we recommend using the Docker setup instead. - -To set up your local Docker environment, run: - -```shell -sh bin/local/setup-docker-env.sh -``` - -This script will automatically handle the complete Docker environment setup process. - -### What the Setup Script Does - -The setup script performs the following operations: - -#### 1. Environment Verification -- ✅ Checks that Docker is running -- ✅ Verifies required files exist - -#### 2. Configuration Setup -- 📁 Copies `bin/local/.env.local` to `.env` - - Uses local development configuration (different from `.env.dist`) - - Sets appropriate database credentials and WordPress settings - -#### 3. Docker Container Management -- 🐳 Runs `composer run docker:build` - - Executes `sh bin/build-docker.sh` to create the Docker container - - Builds WordPress environment with PHP 8.2 -- 🚀 Runs `docker compose up -d` to start the container in detached mode - - Creates container named `wpgraphql-logging-wordpress-1` - - Sets up WordPress with test database - -#### 4. Code Coverage Setup -- 🔧 Installs and configures PCOV extension (preferred for performance) -- 🔄 Falls back to XDebug if PCOV installation fails -- ⚙️ Configures coverage settings automatically -- 🔄 Restarts container to ensure extensions are loaded - -#### 5. WordPress Installation -- 📝 Installs WordPress if not already present -- 🔌 Activates the plugin automatically -- ✅ Verifies the installation is working correctly - -### Running Tests Locally - -Once setup is complete, you can run tests using Composer: - -<[!NOTE] -< Ensure the docker container is running before executing tests. You can run `composer run docker:start` to start it. - -```shell -# Run unit tests with coverage -composer run test:unit:coverage - -# Run all tests -composer run test - -# Run E2E tests -composer run test:e2e -``` - -For a full list of available test commands, see the [Usage](#usage) section above. - ---- - -## Troubleshooting - -### Container Issues - -```shell -# Check container status -docker ps | grep wpgraph-logging - -# Restart containers if needed -docker compose restart - -# View container logs -docker compose logs wpgraph-logging-wordpress-1 -``` - -### Permission Issues - -```shell -# Fix test output permissions -docker exec wpgraphql-logging-wordpress-1 chmod 777 -R tests/_output -``` - -### Coverage Driver Issues - -```shell -# Check which coverage driver is available -docker exec wpgraphql-logging-wordpress-1 php -m | grep -E "(pcov|xdebug)" - -# Re-run setup if coverage isn't working -sh bin/local/setup-docker-env.sh -``` - -### WordPress Database Issues - -```shell -# Reinstall WordPress -docker exec wpgraphql-logging-wordpress-1 wp core install \ - --url=http://localhost \ - --title="Test Site" \ - --admin_user=admin \ - --admin_password=admin \ - --admin_email=admin@example.com \ - --allow-root -``` - -### Clean Up Environment - -```shell -# Stop containers -docker compose down - -# Remove containers and volumes (complete cleanup) -docker compose down -v -``` - ---- - -## Contributing - -If you feel like something is missing or you want to add tests or testing documentation, we encourage you to contribute! Please check out our [Contributing Guide](https://github.com/wpengine/hwptoolkit/blob/main/CONTRIBUTING.md) for more details. diff --git a/plugins/wpgraphql-logging/docs/index.md b/plugins/wpgraphql-logging/docs/index.md deleted file mode 100644 index 04214ce6..00000000 --- a/plugins/wpgraphql-logging/docs/index.md +++ /dev/null @@ -1,204 +0,0 @@ -# WPGraphQL Logging - -## Table of Contents - -- [Project Structure](#project-structure) -- [Key Features](#key-features) -- [Setup](#setup) -- [Basic Configuration](#basic-configuration) -- [Viewing Logs](#viewing-logs) -- [Uninstallation and Data Cleanup](#uninstallation-and-data-cleanup) -- [How-to Guides](#how-to-guides) -- [Reference](#reference) - ---- - - -## Project Structure - -```text -wpgraphql-logging/ -├── docs/ # Docs for extending the plugin. Contains developer docs. -├── src/ # Main plugin source code -│ ├── Admin/ # Admin settings, menu, and settings page logic -│ ├── Settings/ # Admin settings functionality for displaying and saving data. -│ ├── Events/ # Event logging, pub/sub event manager for extending the logging. -│ ├── Logger/ # Logger service, Monolog handlers & processors -│ ├── Api/ # Api interfaces for fetching and writing log data -│ ├── Database/ # Database entity and helper -│ ├── Handlers/ # Monolog WordPress database handler for logging data -│ ├── Processors/ # Monolog processors for data sanitization and request headers -│ ├── Rules/ # Rules and RuleManager to decide whether to log a query -│ ├── Scheduler/ # Automated data cleanup and maintenance tasks -│ ├── Plugin.php # Main plugin class (entry point) -│ └── Autoloader.php # PSR-4 autoloader -├── tests/ # All test suites -│ ├── wpunit/ # WPBrowser/Codeception unit tests -├── [wpgraphql-logging.php] -├── [activation.php] -├── [composer.json] -├── [deactivation.php] -├── [TESTING.md] -├── [README.md] -``` - ---- - -## Key Features - -- **End-to-end GraphQL lifecycle logging** - - **Pre Request** (`do_graphql_request`): captures `query`, `variables`, `operation_name`. - - **Before Execution** (`graphql_before_execute`): snapshots request `params`. - - **Before Response Returned** (`graphql_return_response`): inspects `response`; auto-elevates level to Error when GraphQL `errors` are present (adds `errors` to context). - -- **Developer-friendly pub/sub and transform system** - - Programmatic API: `Plugin::on($event, $listener)`, `Plugin::transform($event, $callable)`, `Plugin::emit($event, $payload)`. - - Prioritized execution: lower priority runs earlier for both subscribers and transforms. - - WordPress bridges: actions `wpgraphql_logging_event_{event}` and filters `wpgraphql_logging_filter_{event}` to integrate with standard hooks. - - Safe-by-default: exceptions in listeners/transforms are caught and logged; they do not break the pipeline. - - See: Reference › Events (`docs/reference/events.md`) and How‑to guides (`docs/how-to/events_pub_sub.md`, `docs/how-to/events_add_context.md`). - -- **Extensible Monolog pipeline** - - Default handler: `WordPressDatabaseHandler` stores logs in `{$wpdb->prefix}wpgraphql_logging`. - - Add handlers via filter `wpgraphql_logging_default_handlers` (e.g., file, Slack, HTTP, etc.). - - Add processors via filter `wpgraphql_logging_default_processors` (e.g., enrich records with user/site data). - - Customize `default_context` via `wpgraphql_logging_default_context`. - - Use `LoggerService::get_instance()` to build custom channels, handlers, processors. - -- **Configurable rule-based logging** - - Built-in rules: enabled toggle, IP restrictions, exclude queries, sampling rate, null query guard, response logging toggle. - - All rules are orchestrated by a `RuleManager` ensuring logs only emit when all rules pass. - - Extend rules: hook `wpgraphql_logging_rule_manager` to add custom `LoggingRuleInterface` implementations. - -- **Automated data management** - - **Daily cleanup scheduler**: removes old logs based on retention. - - **Configurable retention period**: choose days to keep (default 30). - - **Manual cleanup**: trigger from the admin UI. - - **Data sanitization**: built-in `DataSanitizationProcessor` removes/anonymizes/truncates sensitive fields with recommended or custom rules. - -- **Admin UI for operations** - - Logs list view with filters (level, date range) and CSV export. - - Bulk delete actions and visibility controls. - -- **Composable and testable architecture** - - Clear separation: Events bus, Logger service, Rules, Processors, Handlers. - - Designed for extension via interfaces, filters, and helper APIs. - ---- - -## Setup - -Once the plugin is activated, you can activate and configure the plugin under Settings -> WPGraphQL Logging - -### Basic Configuration - -![Basic Configuration](screenshots/admin_configuration_basic.png) - -- **Enabled**: The master switch to turn logging on or off. -- **IP Restrictions**: A comma-separated list of IPv4/IPv6 addresses. When set, only requests originating from these IPs will be logged. This is particularly useful for developers who wish to log only their own queries. -- **Exclude Queries**: A comma-separated list of GraphQL query or mutation names to be excluded from logging. This helps reduce noise by ignoring frequent or uninteresting operations. -- **Data Sampling Rate**: A dropdown to select the percentage of requests that will be logged. This is useful for managing log volume on high-traffic sites by only capturing a sample of the total requests. -- **Log Points**: A multi-select field to choose the specific WPGraphQL lifecycle events for which data should be logged. -- **Log Response**: A toggle to determine whether the GraphQL response body should be included in the log. Disabling this can reduce the size of your log data. - ->[!NOTE] -> Logging enablement is determined by a set of rules managed by a `RuleManager`. All rules must pass to log a request. See the Logger reference for the RuleManager hook: [wpgraphql_logging_rule_manager](reference/logging.md#trait-loggerlogginghelper). - - - -### Data Management - -![Data Management](screenshots/admin_configuration_data_management.png) - -- **Enable Data Deletion**: A toggle to enable a daily WP-Cron job that automatically deletes old log entries based on the retention period. -- **Log Retention Period**: Specify the number of days to keep log data before it is automatically deleted. -- **Enable Data Sanitization**: The master switch to turn data sanitization on or off. When enabled, sensitive data is cleaned from logs before being stored. -- **Data Sanitization Method**: Choose between two sanitization methods: - - **Recommended Rules (Default)**: Uses pre-configured rules to automatically sanitize common sensitive fields in WordPress and WPGraphQL. The following fields are sanitized: - - `request.app_context.viewer.data` (User data object) - - `request.app_context.viewer.allcaps` (User capabilities) - - `request.app_context.viewer.cap_key` (Capability keys) - - `request.app_context.viewer.caps` (User capability array) - - **Custom Rules**: Provides granular control over sanitization with the following options: - - **Fields to Remove**: A comma-separated list of field paths (e.g., `request.app_context.viewer.data`) to completely remove from the log. - - **Fields to Anonymize**: A comma-separated list of field paths whose values will be replaced with `***`. - - **Fields to Truncate**: A comma-separated list of field paths whose string values will be truncated to 50 characters. - - -## Viewing Logs - -Once configured to log data you can find logs under "GraphQL Logs" in the WordPress Menu. - -![Admin View](screenshots/admin_view.png) - -This extends the WordPress `WP_List_Table` class but you can do the following. - -### Download the log - -You can download the log as CSV format e.g. - -```csv -ID,Date,Level,"Level Name",Message,Channel,Query,Context,Extra -5293,"2025-10-06 15:41:34",200,INFO,"WPGraphQL Response",wpgraphql_logging,"{ posts(first: 10) ...""memory_peak_usage"":""18 MB""}" -``` - - -### Filtering Logs - -You can filter the log by - -1. Level -2. Start Date -3. End Date - -![Admin View with Filters](screenshots/admin_view_filters.png) - ->[!NOTE] -> The default UI highlights Info and Error levels. To customize visible columns and sorting, filter `wpgraphql_logging_logs_table_column_headers` (see Admin reference). - - -### Bulk Actions - -Currently you can delete selected or all logs. - - -## Uninstallation and Data Cleanup - -By default, WPGraphQL Logging preserves all logged data when the plugin is deactivated to prevent accidental data loss. If you want to completely remove all plugin data (including database tables) when deactivating the plugin, you must explicitly enable this behavior. - -### Enabling Database Cleanup on Deactivation - -To enable automatic database cleanup when the plugin is deactivated, add the following constant to your `wp-config.php` file or in a must-use plugin: - -```php -define( 'WP_GRAPHQL_LOGGING_UNINSTALL_PLUGIN', true ); -``` - -> [!WARNING] -> **Data Loss Warning**: When `WP_GRAPHQL_LOGGING_UNINSTALL_PLUGIN` is defined as `true`, deactivating the plugin will permanently delete all logged data and drop the plugin's database tables. This action is irreversible. - - -## How to Guides - -### Admin -- [How to replace the database log service](how-to/logger_replace_log_store_service.md) -- [How to add a new Settings tab to WPGraphQL Logging](how-to/admin_add_new_tab.md) -- [How to add a new field to an existing tab and query it](how-to/admin_add_fields.md) -- [How to add a new column to the Logs admin grid](how-to/admin_add_view_column.md) - -### Events -- [How to add context data to a logged WPGraphQL event](how-to/events_add_context.md) -- [How to use the WPGraphQL Logging events pub/sub system](how-to/events_pub_sub.md) - -### Logging - -- [How to Add a New Handler (File Logging)](how-to/logger_add_new_handler.md) -- [How to Add a New Processor](how-to/logger_add_new_processor.md) -- [How to Add a New Rule (Query must contain string)](how-to/logger_add_new_rule.md) - - -## Reference - -- Admin: [Actions/Filters](reference/admin.md) -- Events: [Actions/Filters](reference/events.md) -- Logging: [Actions/Filters](reference/logging.md) diff --git a/plugins/wpgraphql-logging/docs/reference/admin.md b/plugins/wpgraphql-logging/docs/reference/admin.md deleted file mode 100644 index 348b4a9a..00000000 --- a/plugins/wpgraphql-logging/docs/reference/admin.md +++ /dev/null @@ -1,378 +0,0 @@ -## Admin Reference - -The WPGraphQL Logging plugin provides several filters and actions in the Admin area that allow developers to extend and customize functionality. This reference documents all available hooks with real-world examples. - -## Table of Contents - -- [SettingsPage](#class-settingspage) -- [Settings\ConfigurationHelper](#class-settingsconfigurationhelper) -- [Settings\SettingsFormManager](#class-settingssettingsformmanager) -- [ViewLogsPage](#class-viewlogspage) -- [Settings\Templates\admin.php and View Templates](#class-settingstemplatesadminphp-and-view-templates) - - ---- - - -### Class: `SettingsPage` -Source: - -#### Action: `wpgraphql_logging_settings_init` -Fires once the Settings Page singleton is initialized. - -Parameters: -- `$instance` (SettingsPage) Settings page instance - -Example: -```php -add_action( 'wpgraphql_logging_settings_init', function( $settings_page ) { - add_action( 'admin_notices', function() { - echo '

Custom notice.

- }); -}, 10, 1 ); -``` - -#### Action: `wpgraphql_logging_admin_enqueue_scripts` -Fires when scripts/styles are enqueued for the Settings page. - -Parameters: -- `$hook_suffix` (string) Current admin page hook - -Example: -```php -add_action( 'wpgraphql_logging_admin_enqueue_scripts', function( $hook_suffix ) { - wp_enqueue_style( 'my-logging-admin', plugins_url( 'assets/css/admin.css', __FILE__ ), [], '1.0.0' ); -}, 10, 1 ); -``` - -#### Filter: `wpgraphql_logging_admin_template_path` -Filters the admin template path used to render the Settings page. - -Parameters: -- `$template_path` (string) Default template path - -Returns: string - -Example: -```php -add_filter( 'wpgraphql_logging_admin_template_path', function( $template_path ) { - return plugin_dir_path( __FILE__ ) . 'templates/custom-admin.php'; -}); -``` - ---- - -### Class: `Settings\Fields\SettingsFieldCollection` -Source: - -#### Action: `wpgraphql_logging_settings_field_collection_init` -Allows developers to register additional settings tabs/fields. - -Parameters: -- `$collection` (SettingsFieldCollection) The collection instance - -Example: -```php -add_action( 'wpgraphql_logging_settings_field_collection_init', function( $collection ) { - $collection->add_tab( new \MyPlugin\Admin\Settings\Fields\Tab\MyCustomTab() ); -}, 10, 1 ); -``` - ->[NOTE] -> See our how to guide [How to add a new Settings tab to WPGraphQL Logging](../how-to/admin_add_new_tab.md) - - ---- - -### Class: `Settings\Tab\BasicConfigurationTab` -Source: - -#### Filter: `wpgraphql_logging_basic_configuration_fields` -Filters the field definitions for the Basic Configuration tab. - -Parameters: -- `$fields` (array) Map of field id => field object - -Returns: array - -Example: -```php -add_filter( 'wpgraphql_logging_basic_configuration_fields', function( $fields ) { - $fields['my_setting'] = new \WPGraphQL\Logging\Admin\Settings\Fields\Field\CheckboxField( - 'my_setting', - 'basic_configuration', - __( 'My Setting', 'my-plugin' ) - ); - return $fields; -}); -``` - ---- - -### Class: `Settings\Tab\DataManagementTab` -Source: - -#### Filter: `wpgraphql_logging_data_management_fields` -Filters the field definitions for the Data Management tab. - -Parameters: -- `$fields` (array) Map of field id => field object - -Returns: array - -Example: -```php -add_filter( 'wpgraphql_logging_data_management_fields', function( $fields ) { - $fields['my_purge_days'] = new \WPGraphQL\Logging\Admin\Settings\Fields\Field\TextIntegerField( - 'my_purge_days', - 'data_management', - __( 'Purge After (days)', 'my-plugin' ) - ); - return $fields; -}); -``` - ---- - -### Class: `Settings\ConfigurationHelper` -Source: - -#### Filter: `wpgraphql_logging_settings_group_option_key` -Filters the option key used to store settings. - -Parameters: -- `$option_key` (string) - -Returns: string - -Example: -```php -add_filter( 'wpgraphql_logging_settings_group_option_key', function( $option_key ) { - return $option_key . '_' . wp_get_environment_type(); -}); -``` - -#### Filter: `wpgraphql_logging_settings_group_settings_group` -Filters the settings group name. - -Parameters: -- `$settings_group` (string) - -Returns: string - -Example: -```php -add_filter( 'wpgraphql_logging_settings_group_settings_group', function( $group ) { - return is_multisite() ? 'network_' . $group : $group; -}); -``` - ---- - -### Class: `Settings\SettingsFormManager` -Source: - -#### Action: `wpgraphql_logging_settings_form_manager_init` -Fires when the settings form manager is initialized. - -Parameters: -- `$instance` (SettingsFormManager) - -Example: -```php -add_action( 'wpgraphql_logging_settings_form_manager_init', function( $manager ) { - // Place for validation/transform hooks tied to registration lifecycle -}, 10, 1 ); -``` - ---- - -### Class: `ViewLogsPage` -Source: - -#### Action: `wpgraphql_logging_view_logs_init` -Fires once the View Logs page singleton is initialized. - -Parameters: -- `$instance` (ViewLogsPage) - -Example: -```php -add_action( 'wpgraphql_logging_view_logs_init', function( $view_logs_page ) { - // e.g. register custom columns or UI -}, 10, 1 ); -``` - -#### Action: `wpgraphql_logging_view_logs_admin_enqueue_scripts` -Fires when scripts/styles are enqueued for the View Logs page. - -Parameters: -- `$hook_suffix` (string) - -Example: -```php -add_action( 'wpgraphql_logging_view_logs_admin_enqueue_scripts', function( $hook_suffix ) { - wp_enqueue_script( 'my-view-logs', plugins_url( 'assets/js/view-logs.js', __FILE__ ), [ 'jquery' ], '1.0.0', true ); -}, 10, 1 ); -``` - -#### Filter: `wpgraphql_logging_filter_redirect_url` -Filters the redirect URL after submitting filters. - -Parameters: -- `$redirect_url` (string) -- `$filters` (array) - -Returns: string - -Example: -```php -add_filter( 'wpgraphql_logging_filter_redirect_url', function( $redirect_url, $filters ) { - return add_query_arg( 'my_flag', '1', $redirect_url ); -}, 10, 2 ); -``` ---- - -### Class: `View\List\ListTable` -Source: - -#### Filter: `wpgraphql_logging_logs_table_column_headers` -Filters the table columns and sorting metadata. - -Parameters: -- `$column_headers` (array) [ columns, hidden, sortable, primary ] - -Returns: array - -Example: -```php -add_filter( 'wpgraphql_logging_logs_table_column_headers', function( $headers ) { - $headers[0]['app_name'] = __( 'App', 'my-plugin' ); - return $headers; -}); -``` - -#### Filter: `wpgraphql_logging_logs_table_query_args` -Filters the repository query args used to fetch logs. - -Parameters: -- `$args` (array) - -Returns: array - -Example: -```php -add_filter( 'wpgraphql_logging_logs_table_query_args', function( $args ) { - $args['where'][] = "JSON_EXTRACT(context, '$.app_id') IS NOT NULL"; - return $args; -}); -``` - -#### Filter: `wpgraphql_logging_logs_table_column_value` -Filters the rendered value for each column. - -Parameters: -- `$value` (mixed) -- `$item` (\WPGraphQL\Logging\Logger\Database\WordPressDatabaseEntity) -- `$column_name` (string) - -Returns: mixed - -Example: -```php -add_filter( 'wpgraphql_logging_logs_table_column_value', function( $value, $item, $column ) { - if ( 'message' === $column ) { - return wp_trim_words( (string) $value, 20 ); - } - return $value; -}, 10, 3 ); -``` - -#### Filter: `wpgraphql_logging_logs_table_where_clauses` -Filters the computed WHERE clauses before querying. - -Parameters: -- `$where_clauses` (array) -- `$request` (array) - -Returns: array - -Example: -```php -add_filter( 'wpgraphql_logging_logs_table_where_clauses', function( $where, $request ) { - if ( ! empty( $request['status_code'] ) ) { - $code = absint( $request['status_code'] ); - $where[] = "JSON_EXTRACT(context, '$.status_code') = {$code}"; - } - return $where; -}, 10, 2 ); -``` ---- - -### Class: `View\Download\DownloadLogService` -Source: - -#### Filter: `wpgraphql_logging_csv_filename` -Filters the CSV filename used for a single log export. - -Parameters: -- `$filename` (string) - -Returns: string - -Example: -```php -add_filter( 'wpgraphql_logging_csv_filename', function( $filename ) { - return 'myapp_' . gmdate( 'Ymd_His' ) . '.csv'; -}); -``` - -#### Filter: `wpgraphql_logging_csv_headers` -Filters the CSV column headers. - -Parameters: -- `$headers` (array) -- `$log_id` (int) -- `$log` (\WPGraphQL\Logging\Logger\Database\WordPressDatabaseEntity) - -Returns: array - -Example: -```php -add_filter( 'wpgraphql_logging_csv_headers', function( $headers ) { - return array_merge( $headers, [ 'Environment', 'Endpoint' ] ); -}, 10, 3 ); -``` - -#### Filter: `wpgraphql_logging_csv_content` -Filters the CSV row values. - -Parameters: -- `$content` (array) -- `$log_id` (int) -- `$log` (\WPGraphQL\Logging\Logger\Database\WordPressDatabaseEntity) - -Returns: array - -Example: -```php -add_filter( 'wpgraphql_logging_csv_content', function( $content, $log_id, $log ) { - $context = $log->get_context(); - return array_merge( $content, [ - $context['environment'] ?? 'prod', - $context['headless_endpoint'] ?? '', - ] ); -}, 10, 3 ); -``` - ---- - -### Class: `Settings\Templates\admin.php` and View Templates -Source: `src/Admin/Settings/Templates/admin.php`, `src/Admin/View/Templates/WPGraphQLLogger*.php` - -These templates are referenced by the template path filters above and do not define hooks themselves. - -**Template Files:** -- `WPGraphQLLoggerFilters.php` - Filter controls template -- `WPGraphQLLoggerList.php` - Logs list table template -- `WPGraphQLLoggerView.php` - Single log detail view template diff --git a/plugins/wpgraphql-logging/docs/reference/events.md b/plugins/wpgraphql-logging/docs/reference/events.md deleted file mode 100644 index 068013bc..00000000 --- a/plugins/wpgraphql-logging/docs/reference/events.md +++ /dev/null @@ -1,142 +0,0 @@ -## Events Reference - -The WPGraphQL Logging plugin exposes a lightweight pub/sub system for WPGraphQL lifecycle events and bridges them to standard WordPress actions/filters. - -## Table of Contents - -- [Events\Events](#class-eventsevents) -- [Events\EventManager](#class-eventseventmanager) - - ---- - -### Class: `Events\Events` -Source: - -Constants that map to WPGraphQL core hooks: - -- `Events::PRE_REQUEST` → `do_graphql_request` -- `Events::BEFORE_GRAPHQL_EXECUTION` → `graphql_before_execute` -- `Events::BEFORE_RESPONSE_RETURNED` → `graphql_return_response` -- `Events::REQUEST_DATA` → `graphql_request_data` (filter) -- `Events::RESPONSE_HEADERS_TO_SEND` → `graphql_response_headers_to_send` (filter) -- `Events::REQUEST_RESULTS` → `graphql_request_results` (filter) - -Use these with the `Plugin` helpers or the `EventManager` directly. - - ---- - -### Class: `Events\EventManager` -Source: - -#### Action: `wpgraphql_logging_event_{event_name}` -Bridged WordPress action fired whenever an internal event is published. (and data logged) - -Parameters: -- `$payload` (array) Published payload, typically includes `context` and sometimes `level` - -Example: -```php -add_action( 'wpgraphql_logging_event_do_graphql_request', function( array $payload ) { - // Do something with the payload. -}, 10, 1 ); -``` - -#### Filter: `wpgraphql_logging_filter_{event_name}` -Bridged WordPress filter applied whenever an internal event payload is transformed and allow you to log data. - -Parameters: -- `$payload` (array) Mutable payload; return the updated array - -Returns: array - -Example: -```php -add_filter( 'wpgraphql_logging_filter_graphql_return_response', function( array $payload ) { - $payload['context']['wpgraphql-content-blocks'] = ['no_of_blocks' => 100]; - return $payload; -}, 10, 1 ); -``` - -Programmatic API: - -- Subscribe: -```php -use WPGraphQL\Logging\Plugin; -use WPGraphQL\Logging\Events\Events; - -Plugin::on( Events::PRE_REQUEST, function( array $payload ): void { - // ... -}, 5 ); -``` - -- Transform: -```php -use WPGraphQL\Logging\Plugin; -use WPGraphQL\Logging\Events\Events; -use Monolog\Level; - -Plugin::transform( Events::BEFORE_RESPONSE_RETURNED, function( array $payload ): array { - $payload['context']['custom_key'] = 'custom_value'; - $payload['level'] = Level::Debug; - return $payload; -}, 10 ); -``` - - ---- - -### Class: `Events\QueryActionLogger` -Source: - -Hooks into WPGraphQL actions and publishes/records events via the logger service. - -#### Action: `do_graphql_request` (mapped from `Events::PRE_REQUEST`) -Logged as “WPGraphQL Pre Request”. - -Parameters: -- `$query` (string|null) -- `$operation_name` (string|null) -- `$variables` (array|null) - -Example: -```php -add_action( 'init', function() { - \WPGraphQL\Logging\Plugin::on( \WPGraphQL\Logging\Events\Events::PRE_REQUEST, function( array $payload ): void { - $ctx = $payload['context'] ?? []; - // ... - } ); -} ); -``` - ---- - - -### Quick Start - -```php -use WPGraphQL\Logging\Plugin; -use WPGraphQL\Logging\Events\Events; - -// Subscribe (read-only) -Plugin::on( Events::PRE_REQUEST, function( array $payload ): void { - // Inspect $payload['context'] -}, 10 ); - -// Transform (mutate payload before it is logged/emitted) -Plugin::transform( Events::PRE_REQUEST, function( array $payload ): array { - $payload['context']['env'] = wp_get_environment_type(); - return $payload; -}, 10 ); -``` - ---- - -### Further Reading - -- [WPGraphQL Documentation](https://www.wpgraphql.com/docs/) -- [WPGraphQL Actions and Filters](https://www.wpgraphql.com/docs/actions-and-filters/) -- [Observer Pattern](https://en.wikipedia.org/wiki/Observer_pattern) -- [Publish-Subscribe Pattern](https://en.wikipedia.org/wiki/Publish%E2%80%93subscribe_pattern) -- [WordPress Plugin API (Actions & Filters)](https://developer.wordpress.org/plugins/hooks/) diff --git a/plugins/wpgraphql-logging/docs/reference/logging.md b/plugins/wpgraphql-logging/docs/reference/logging.md deleted file mode 100644 index bc8cdce3..00000000 --- a/plugins/wpgraphql-logging/docs/reference/logging.md +++ /dev/null @@ -1,330 +0,0 @@ -## Logger Reference - -The WPGraphQL Logging subsystem is built on [Monolog](https://github.com/Seldaek/monolog). This reference documents the Logger classes under `src/Logger` and all available WordPress actions/filters for extending behavior. - -## Table of Contents - -- [Logger\LoggerService](#class-loggerloggerservice) -- [Logger\LoggingHelper](#trait-loggerlogginghelper) -- [Logger\Handlers\WordPressDatabaseHandler](#class-loggerhandlerswordpressdatabasehandler) -- [Logger\Processors\RequestHeadersProcessor](#class-loggerprocessorsrequestheadersprocessor) -- [Logger\Processors\DataSanitizationProcessor](#class-loggerprocessorsdatasanitizationprocessor) -- [Logger\Database\WordPressDatabaseEntity](#class-loggerdatabasewordpressdatabaseentity) -- [Logger\Scheduler\DataDeletionScheduler](#class-loggerschedulerdatadeletionscheduler) -- [Quick Start](#quick-start) -- [Available Log Levels](#available-log-levels) - - ---- - -### Class: `Logger\LoggerService` -Source: - -Manages Monolog instances (per-channel singleton). Provides default handlers, processors, and context. - -#### Filter: `wpgraphql_logging_default_processors` -Filters the default processor list. - -Parameters: -- `$processors` (array) Current processors - -Returns: array - -Example: -```php -add_filter( 'wpgraphql_logging_default_processors', function( array $processors ) { - $processors[] = new \MyPlugin\Logging\UserContextProcessor(); - return $processors; -}); -``` - -#### Filter: `wpgraphql_logging_default_buffer_limit` -Filters the default buffer limit for the BufferHandler. - -Parameters: -- `$buffer_limit` (int) Current buffer limit (default: 50) - -Returns: int - -Example: -```php - -add_filter( 'wpgraphql_logging_default_buffer_limit', function( int $buffer_limit ) { - // Increase buffer limit for high-traffic sites - return 100; -}); - - -``` - - - -#### Filter: `wpgraphql_logging_default_handlers` -Filters the default handler list. - -Parameters: -- `$handlers` (array) Current handlers - -Returns: array - -Example: -```php -use Monolog\Handler\RotatingFileHandler; -use Monolog\Level; - -add_filter( 'wpgraphql_logging_default_handlers', function( array $handlers ) { - $handlers[] = new RotatingFileHandler( WP_CONTENT_DIR . '/logs/wpgraphql.log', 7, Level::Info ); - return $handlers; -}); -``` - -#### Filter: `wpgraphql_logging_default_context` -Filters the default context merged into every record. - -Parameters: -- `$context` (array) Current default context - -Returns: array - -Example: -```php -add_filter( 'wpgraphql_logging_default_context', function( array $context ) { - $context['environment'] = wp_get_environment_type(); - $context['multisite'] = is_multisite(); - return $context; -}); -``` - - ---- - -### Trait: `Logger\LoggingHelper` -Source: - -Common helpers used by logger-aware classes; composes a `RuleManager` and evaluates whether logging is enabled and which events are selected. - -#### Filter: `wpgraphql_logging_rule_manager` -Allows custom rules to be added to the `RuleManager`. - -Parameters: -- `$rule_manager` (RuleManager) The rule manager instance - -Returns: RuleManager - -Example: -```php -add_filter( 'wpgraphql_logging_rule_manager', function( $rule_manager ) { - $rule_manager->add_rule( new \MyPlugin\Logging\Rules\BlockPrivateIPsRule() ); - return $rule_manager; -}); -``` - -#### Filter: `wpgraphql_logging_is_enabled` -Filters the final decision (true/false) for whether logging is enabled for the current request. - -Parameters: -- `$is_enabled` (bool) Computed result from rules -- `$config` (array) Current logging configuration - -Returns: bool - -Example: -```php -add_filter( 'wpgraphql_logging_is_enabled', function( bool $enabled, array $config ) { - if ( defined( 'WPGRAPHQL_LOGGING_FORCE_DISABLE' ) && WPGRAPHQL_LOGGING_FORCE_DISABLE ) { - return false; - } - return $enabled; -}, 10, 2 ); -``` - - ---- - -### Class: `Logger\Handlers\WordPressDatabaseHandler` -Source: - -Monolog handler that persists records to the WordPress database via `DatabaseEntity`. - -Hooks: None. - - ---- - -### Class: `Logger\Processors\RequestHeadersProcessor` -Source: - -Adds request headers to the record `extra` data. - -Hooks: None. - - ---- - -### Class: `Logger\Processors\DataSanitizationProcessor` -Source: - -Sanitizes sensitive fields in record `context` and `extra` based on settings. - -#### Filter: `wpgraphql_logging_data_sanitization_enabled` -Controls whether sanitization is active. - -Parameters: -- `$enabled` (bool) From settings - -Returns: bool - -Example: -```php -add_filter( 'wpgraphql_logging_data_sanitization_enabled', function( $enabled ) { - return $enabled && ! defined( 'WPGRAPHQL_LOGGING_TRUSTED_ENV' ); -}); -``` - -#### Filter: `wpgraphql_logging_data_sanitization_rules` -Filters the active rule map (field path => action). - -Parameters: -- `$rules` (array) Computed rules (recommended or custom) - -Returns: array - -Example: -```php -add_filter( 'wpgraphql_logging_data_sanitization_rules', function( array $rules ) { - $rules['request.params.password'] = 'remove'; - return $rules; -}); -``` - -#### Filter: `wpgraphql_logging_data_sanitization_recommended_rules` -Filters the built-in recommended rules prior to use. - -Parameters: -- `$rules` (array) - -Returns: array - -#### Filter: `wpgraphql_logging_data_sanitization_record` -Filters the final `LogRecord` after sanitization is applied. - -Parameters: -- `$record` (Monolog\LogRecord) - -Returns: Monolog\LogRecord - - ---- - -### Class: `Logger\Database\WordPressDatabaseEntity` -Source: - -Represents a single log entry and provides persistence helpers. - -#### Filter: `wpgraphql_logging_allowed_orderby_columns` -Filters the allowed columns for ORDER BY in `find_logs()` queries. - -**Security:** This filter adds whitelist validation to prevent SQL injection in ORDER BY clauses. Only columns in this array can be used for sorting. - -Parameters: -- `$allowed_columns` (array) Default allowed columns: `['id', 'datetime', 'level', 'level_name', 'channel', 'message']` - -Returns: array - -Example: -```php -// Add custom column to allowed ORDER BY list -add_filter( 'wpgraphql_logging_allowed_orderby_columns', function( array $columns ) { - $columns[] = 'custom_field'; - return $columns; -}); -``` - -**Note:** If an invalid column is requested, the query will fallback to ordering by `id` (default). - - ---- - -### Class: `Logger\Scheduler\DataDeletionScheduler` -Source: - -Schedules and performs periodic deletion of old logs according to retention settings. - -#### Action: `wpgraphql_logging_deletion_cleanup` -Cron hook fired to perform deletion. You can also trigger it manually with `do_action` or WP-CLI cron. - -Parameters: None - -Example: -```php -// Manually trigger cleanup (e.g., in a maintenance task) -do_action( 'wpgraphql_logging_deletion_cleanup' ); -``` - -#### Action: `wpgraphql_logging_cleanup_error` -Fired when an exception occurs during cleanup. - -Parameters: -- `$payload` (array) Includes: `error_message`, `retention_days`, `timestamp` - -Example: -```php -add_action( 'wpgraphql_logging_cleanup_error', function( array $payload ) { - error_log( '[WPGraphQL Logging] Cleanup error: ' . $payload['error_message'] ); -}, 10, 1 ); -``` - - ---- - -### Quick Start - -```php -use WPGraphQL\Logging\Logger\LoggerService; -use Monolog\Level; - -// Default logger -$logger = LoggerService::get_instance(); - -// Context is merged with defaults (WP version, plugin version, etc.) -$logger->info( 'User performed action', [ 'user_id' => 123 ] ); - -// Custom channel with extra handlers/processors -$logger = LoggerService::get_instance( - 'my_channel', - null, // use default handlers via filter - null, // use default processors via filter - [ 'component' => 'catalog' ] -); - -// Generic form -$logger->log( Level::Debug, 'Debug details', [ 'trace_id' => 'abc123' ] ); -``` - - ---- - -### Available Log Levels - -WPGraphQL Logging supports standard PSR-3/Monolog levels: - -| Level | Method | -| --- | --- | -| `EMERGENCY` | `$logger->emergency()` | -| `ALERT` | `$logger->alert()` | -| `CRITICAL` | `$logger->critical()` | -| `ERROR` | `$logger->error()` | -| `WARNING` | `$logger->warning()` | -| `NOTICE` | `$logger->notice()` | -| `INFO` | `$logger->info()` | -| `DEBUG` | `$logger->debug()` | - -You can also call `$logger->log(\Monolog\Level::Info, 'message', $context)`. - ---- - -Further reading: - -- [Monolog Documentation](https://github.com/Seldaek/monolog/blob/main/doc/01-usage.md) -- [PSR-3 Logger Interface](https://www.php-fig.org/psr/psr-3/) -- [WordPress Plugin API (Hooks)](https://developer.wordpress.org/plugins/hooks/) diff --git a/plugins/wpgraphql-logging/docs/screenshots/admin_configuration_basic.png b/plugins/wpgraphql-logging/docs/screenshots/admin_configuration_basic.png deleted file mode 100644 index 2f459e6d..00000000 Binary files a/plugins/wpgraphql-logging/docs/screenshots/admin_configuration_basic.png and /dev/null differ diff --git a/plugins/wpgraphql-logging/docs/screenshots/admin_configuration_data_management.png b/plugins/wpgraphql-logging/docs/screenshots/admin_configuration_data_management.png deleted file mode 100644 index 7c002358..00000000 Binary files a/plugins/wpgraphql-logging/docs/screenshots/admin_configuration_data_management.png and /dev/null differ diff --git a/plugins/wpgraphql-logging/docs/screenshots/admin_how_to_add_column_to_grid.png b/plugins/wpgraphql-logging/docs/screenshots/admin_how_to_add_column_to_grid.png deleted file mode 100644 index 80cca9fe..00000000 Binary files a/plugins/wpgraphql-logging/docs/screenshots/admin_how_to_add_column_to_grid.png and /dev/null differ diff --git a/plugins/wpgraphql-logging/docs/screenshots/admin_how_to_add_field.png b/plugins/wpgraphql-logging/docs/screenshots/admin_how_to_add_field.png deleted file mode 100644 index e4c60b97..00000000 Binary files a/plugins/wpgraphql-logging/docs/screenshots/admin_how_to_add_field.png and /dev/null differ diff --git a/plugins/wpgraphql-logging/docs/screenshots/admin_view.png b/plugins/wpgraphql-logging/docs/screenshots/admin_view.png deleted file mode 100644 index 14cdef89..00000000 Binary files a/plugins/wpgraphql-logging/docs/screenshots/admin_view.png and /dev/null differ diff --git a/plugins/wpgraphql-logging/docs/screenshots/admin_view_filters.png b/plugins/wpgraphql-logging/docs/screenshots/admin_view_filters.png deleted file mode 100644 index c507536a..00000000 Binary files a/plugins/wpgraphql-logging/docs/screenshots/admin_view_filters.png and /dev/null differ diff --git a/plugins/wpgraphql-logging/readme.txt b/plugins/wpgraphql-logging/readme.txt index 4267ec1c..114af323 100644 --- a/plugins/wpgraphql-logging/readme.txt +++ b/plugins/wpgraphql-logging/readme.txt @@ -9,7 +9,7 @@ Stable tag: 0.2.2 License: GPL-2.0-or-later License URI: https://www.gnu.org/licenses/gpl-2.0.html -A WPGraphQL logging plugin that provides visibility into the GraphQL request lifecycle, giving developers the observability needed to quickly identify and resolve bottlenecks in their headless WordPress application. +WPGraphQL Logging plugin provides observability and visibility into the GraphQL request and event lifecycle. This allows users to quickly identify and resolve performance issues and bottlenecks within their headless WordPress application. == Description == diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 098050a6..0bd9e400 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -15,6 +15,16 @@ overrides: importers: .: + dependencies: + remark-cli: + specifier: ^12.0.1 + version: 12.0.1 + remark-frontmatter: + specifier: ^5.0.0 + version: 5.0.0 + remark-preset-lint-recommended: + specifier: ^7.0.1 + version: 7.0.1 devDependencies: '@changesets/changelog-github': specifier: ^0.5.1 @@ -37,6 +47,9 @@ importers: '@wordpress/scripts': specifier: 30.24.0 version: 30.24.0(@playwright/test@1.56.1)(@types/eslint@9.6.1)(@types/node@24.10.0)(@types/webpack@4.41.40)(@wordpress/env@10.34.0(@types/node@24.10.0))(react-dom@19.2.0(react@19.2.0))(react@19.2.0)(stylelint-scss@6.12.1(stylelint@16.24.0(typescript@5.8.3)))(type-fest@4.41.0)(typescript@5.8.3) + remark-gfm: + specifier: ^4.0.1 + version: 4.0.1 rimraf: specifier: ^5.0.5 version: 5.0.10 @@ -1494,6 +1507,30 @@ packages: resolution: {integrity: sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==} engines: {node: '>= 8'} + '@npmcli/config@8.3.4': + resolution: {integrity: sha512-01rtHedemDNhUXdicU7s+QYz/3JyV5Naj84cvdXGH4mgCdL+agmSYaLF4LUG4vMCLzhBO8YtS0gPpH1FGvbgAw==} + engines: {node: ^16.14.0 || >=18.0.0} + + '@npmcli/git@5.0.8': + resolution: {integrity: sha512-liASfw5cqhjNW9UFd+ruwwdEf/lbOAQjLL2XY2dFW/bkJheXDYZgOyul/4gVvEV4BWkTXjYGmDqMw9uegdbJNQ==} + engines: {node: ^16.14.0 || >=18.0.0} + + '@npmcli/map-workspaces@3.0.6': + resolution: {integrity: sha512-tkYs0OYnzQm6iIRdfy+LcLBjcKuQCeE5YLb8KnrIlutJfheNaPvPpgoFEyEFgbjzl5PLZ3IA/BWAwRU0eHuQDA==} + engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0} + + '@npmcli/name-from-folder@2.0.0': + resolution: {integrity: sha512-pwK+BfEBZJbKdNYpHHRTNBwBoqrN/iIMO0AiGvYsp3Hoaq0WbgGSWQR6SCldZovoDpY3yje5lkFUe6gsDgJ2vg==} + engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0} + + '@npmcli/package-json@5.2.1': + resolution: {integrity: sha512-f7zYC6kQautXHvNbLEWgD/uGu1+xCn9izgqBfgItWSx22U0ZDekxN08A1vM8cTxj/cRVe0Q94Ode+tdoYmIOOQ==} + engines: {node: ^16.14.0 || >=18.0.0} + + '@npmcli/promise-spawn@7.0.2': + resolution: {integrity: sha512-xhfYPXoV5Dy4UkY0D+v2KkwvnDfiA/8Mt3sWCGI/hM03NsYIH8ZaG6QzS9x7pje5vHZBZJ2v6VRFVTWACnqcmQ==} + engines: {node: ^16.14.0 || >=18.0.0} + '@opentelemetry/api-logs@0.57.2': resolution: {integrity: sha512-uIX52NnTM0iBh84MShlpouI7UKqkZ7MrUszTmaypHBu4r7NofznSnQRfJ+uUeDtQDj6w8eFGg5KBLDAwAPz1+A==} engines: {node: '>=14'} @@ -2036,18 +2073,27 @@ packages: '@types/cacheable-request@6.0.3': resolution: {integrity: sha512-IQ3EbTzGxIigb1I3qPZc1rWJnH0BmSKv5QYTalEwweFvyBDLSAe24zP0le/hyi7ecGfZVlIVAg4BZqb8WBwKqw==} + '@types/concat-stream@2.0.3': + resolution: {integrity: sha512-3qe4oQAPNwVNwK4C9c8u+VJqv9kez+2MR4qJpoPFfXtgxxif1QbFusvXzK0/Wra2VX07smostI2VMmJNSpZjuQ==} + '@types/connect-history-api-fallback@1.5.4': resolution: {integrity: sha512-n6Cr2xS1h4uAulPRdlw6Jl6s1oG8KrVilPN2yUITEs+K48EzMJJ3W1xy8K5eWuFvjp3R74AOIGSmp2UfBJ8HFw==} '@types/connect@3.4.38': resolution: {integrity: sha512-K6uROf1LD88uDQqJCktA4yzL1YYAK6NgfsI0v/mTgyPKWsX1CnJ0XPSDhViejru1GcRkLWb8RlzFYJRqGUbaug==} + '@types/debug@4.1.12': + resolution: {integrity: sha512-vIChWdVG3LG1SMxEvI/AK+FWJthlrqlTu7fbrlywTkkaONwk/UAGaULXRlf8vkzFBLVm0zkMdCquhL5aOjhXPQ==} + '@types/eslint-scope@3.7.7': resolution: {integrity: sha512-MzMFlSLBqNF2gcHWO0G1vP/YQyfvrxZ0bF+u7mzUdZ1/xK4A4sru+nraZz5i3iEIk1l1uyicaDVTB4QbbEkAYg==} '@types/eslint@9.6.1': resolution: {integrity: sha512-FXx2pKgId/WyYo2jXw63kk7/+TY7u7AziEJxJAnSFzHlqTAS3Ync6SvgYAN/k4/PQpnnVuzoMuVnByKK2qp0ag==} + '@types/estree-jsx@1.0.5': + resolution: {integrity: sha512-52CcUVNFyfb1A2ALocQw/Dd1BQFNmSdkuC3BkZ6iqhdMfQz7JWOFRuJFloOzjk+6WijU56m9oKXFAXc7o3Towg==} + '@types/estree@1.0.8': resolution: {integrity: sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==} @@ -2060,6 +2106,9 @@ packages: '@types/graceful-fs@4.1.9': resolution: {integrity: sha512-olP3sd1qOEe5dXTSaFvQG+02VdRXcdytWLAZsAq1PecU8uqQAhkrnbli7DagjtXKW/Bl7YJbUsa8MPcuc8LHEQ==} + '@types/hast@3.0.4': + resolution: {integrity: sha512-WPs+bbQw5aCj+x6laNGWLH3wviHtoCv/P3+otBhbOhJgG8qtpdAMlTCxLtsTWA7LH1Oh/bFCHsBn0TPS5m30EQ==} + '@types/http-cache-semantics@4.0.4': resolution: {integrity: sha512-1m0bIFVc7eJWyve9S0RnuRgcQqF/Xd5QsUZAZeQFr1Q3/p9JWoQQEqmVy+DPTNpGXwhgIetAoYF8JSc33q29QA==} @@ -2069,6 +2118,9 @@ packages: '@types/http-proxy@1.17.17': resolution: {integrity: sha512-ED6LB+Z1AVylNTu7hdzuBqOgMnvG/ld6wGCG8wFnAzKX5uyW2K3WD52v0gnLCTK/VLpXtKckgWuyScYK6cSPaw==} + '@types/is-empty@1.2.3': + resolution: {integrity: sha512-4J1l5d79hoIvsrKh5VUKVRA1aIdsOb10Hu5j3J2VfP/msDnfTdGPmNp2E1Wg+vs97Bktzo+MZePFFXSGoykYJw==} + '@types/istanbul-lib-coverage@2.0.6': resolution: {integrity: sha512-2QF/t/auWm0lsy8XtKVPG19v3sSOQlJe/YHZgfjb/KBBHOGSV+J2q/S671rcq9uTBrLAXmZpqJiaQbMT+zNU1w==} @@ -2090,12 +2142,18 @@ packages: '@types/keyv@3.1.4': resolution: {integrity: sha512-BQ5aZNSCpj7D6K2ksrRCTmKRLEpnPvWDiLPfoGyhZ++8YtiK9d/3DBKPJgry359X/P1PfruyYwvnvwFjuEiEIg==} + '@types/mdast@4.0.4': + resolution: {integrity: sha512-kGaNbPh1k7AFzgpud/gMdvIm5xuECykRR+JnWKQno9TAXVa6WIVCGTPvYGekIDL4uwCZQSYbUxNBSb1aUo79oA==} + '@types/mime@1.3.5': resolution: {integrity: sha512-/pyBZWSLD2n0dcHE3hq8s8ZvcETHtEuF+3E7XVt0Ig2nvsVQXdghHVcEkIWjy9A0wKfTn97a/PSDYohKIlnP/w==} '@types/minimist@1.2.5': resolution: {integrity: sha512-hov8bUuiLiyFPGyFPE1lwWhmzYbirOXQNNo40+y3zow8aFVTeyn3VWL0VFFfdNddA8S4Vf0Tc062rzyNr7Paag==} + '@types/ms@2.1.0': + resolution: {integrity: sha512-GsCCIZDE/p3i96vtEqx+7dBUGXrc7zeSK3wwPHIaRThS+9OhWIXRqzs4d6k1SVU8g91DrNRWxWUGhp5KXQb2VA==} + '@types/mysql@2.15.26': resolution: {integrity: sha512-DSLCOXhkvfS5WNNPbfn2KdICAmk8lLc+/PNvnPnF7gOdMZCxopXduqv0OQ13y/yA/zXTSikZZqVgybUxOEg6YQ==} @@ -2162,18 +2220,30 @@ packages: '@types/stack-utils@2.0.3': resolution: {integrity: sha512-9aEbYZ3TbYMznPdcdr3SmIrLXwC/AKZXQeCf9Pgao5CKb8CyHuEX5jzWPTkvregvhRJHcpRO6BFoGW9ycaOkYw==} + '@types/supports-color@8.1.3': + resolution: {integrity: sha512-Hy6UMpxhE3j1tLpl27exp1XqHD7n8chAiNPzWfz16LPZoMMoSc4dzLl6w9qijkEb/r5O1ozdu1CWGA2L83ZeZg==} + '@types/tapable@1.0.12': resolution: {integrity: sha512-bTHG8fcxEqv1M9+TD14P8ok8hjxoOCkfKc8XXLaaD05kI7ohpeI956jtDOD3XHKBQrlyPughUtzm1jtVhHpA5Q==} '@types/tedious@4.0.14': resolution: {integrity: sha512-KHPsfX/FoVbUGbyYvk1q9MMQHLPeRZhRJZdO45Q4YjvFkv4hMNghCWTvy7rdKessBsmtz4euWCWAB6/tVpI1Iw==} + '@types/text-table@0.2.5': + resolution: {integrity: sha512-hcZhlNvMkQG/k1vcZ6yHOl6WAYftQ2MLfTHcYRZ2xYZFD8tGVnE3qFV0lj1smQeDSR7/yY0PyuUalauf33bJeA==} + '@types/tough-cookie@4.0.5': resolution: {integrity: sha512-/Ad8+nIOV7Rl++6f1BdKxFSMgmoqEoYbHRpPcx3JEfv8VRsQe9Z4mCXeJBzxs7mbHY/XOZZuXlRNfhpVPbs6ZA==} '@types/uglify-js@3.17.5': resolution: {integrity: sha512-TU+fZFBTBcXj/GpDpDaBmgWk/gn96kMZ+uocaFUlV2f8a6WdMzzI44QBCmGcCiYR0Y6ZlNRiyUyKKt5nl/lbzQ==} + '@types/unist@2.0.11': + resolution: {integrity: sha512-CmBKiL6NNo/OqgmMn95Fk9Whlp2mtvIv+KNpQKN2F4SjvrEesubTRWGYSg+BnWZOnlCaSTU1sMpsBOzgbYhnsA==} + + '@types/unist@3.0.3': + resolution: {integrity: sha512-ko/gIFJRv177XgZsZcBwnqJN5x/Gien8qNOn0D5bQU/zAzVf9Zt3BlcUiLqhV9y4ARk0GbT3tnUiPNgnTXzc/Q==} + '@types/webpack-sources@3.2.3': resolution: {integrity: sha512-4nZOdMwSPHZ4pTEZzSp0AsTM4K7Qmu40UKW4tJDiOVs20UzYF9l+qUe4s0ftfN0pin06n+5cWWDJXH+sbhAiDw==} @@ -2572,6 +2642,10 @@ packages: resolution: {integrity: sha512-j2afSsaIENvHZN2B8GOpF566vZ5WVk5opAiMTvWgaQT8DkbOqsTfvNAvHoRGU2zzP8cPoqys+xHTRDWW8L+/BA==} deprecated: Use your platform's native atob() and btoa() methods instead + abbrev@2.0.0: + resolution: {integrity: sha512-6/mh1E2u2YgEsCHdY0Yx5oW+61gZU+1vXaoiHHrpKeuRNNgFvS+/jrwHiQhB5apAf5oB7UB7E19ol2R2LKH8hQ==} + engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0} + accepts@1.3.8: resolution: {integrity: sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==} engines: {node: '>= 0.6'} @@ -2866,6 +2940,9 @@ packages: peerDependencies: '@babel/core': ^7.0.0 + bail@2.0.2: + resolution: {integrity: sha512-0xO6mYd7JB2YesxDKplafRpsiOzPt9V02ddPCLbY1xYGPOX24NTyN50qnUxgCPcSoYMhKpAuBTjQoRZCAkUDRw==} + balanced-match@1.0.2: resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==} @@ -3047,6 +3124,9 @@ packages: capital-case@1.0.4: resolution: {integrity: sha512-ds37W8CytHgwnhGGTi88pcPyR15qoNkOpYwmMMfnWqqWgESapLqvDx6huFjQ5vqWSn2Z06173XNA7LtMOeUh1A==} + ccount@2.0.1: + resolution: {integrity: sha512-eyrF0jiFpY+3drT6383f1qhkbGsLSifNAjA61IUjZjmLCWjItY6LB9ft9YhoDgwfmclB2zhu51Lc7+95b8NRAg==} + chalk@2.4.2: resolution: {integrity: sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==} engines: {node: '>=4'} @@ -3070,6 +3150,18 @@ packages: resolution: {integrity: sha512-kWWXztvZ5SBQV+eRgKFeh8q5sLuZY2+8WUIzlxWVTg+oGwY14qylx1KbKzHd8P6ZYkAg0xyIDU9JMHhyJMZ1jw==} engines: {node: '>=10'} + character-entities-html4@2.1.0: + resolution: {integrity: sha512-1v7fgQRj6hnSwFpq1Eu0ynr/CDEw0rXo2B61qXrLNdHZmPKgb7fqS1a2JwF0rISo9q77jDI8VMEHoApn8qDoZA==} + + character-entities-legacy@3.0.0: + resolution: {integrity: sha512-RpPp0asT/6ufRm//AJVwpViZbGM/MkjQFxJccQRHmISF/22NBtsHqAWmL+/pmkPWoIUJdWyeVleTl1wydHATVQ==} + + character-entities@2.0.2: + resolution: {integrity: sha512-shx7oQ0Awen/BRIdkjkvz54PnEEI/EjwXDSIZp86/KKdbafHh1Df/RYGBhn4hbe2+uKC9FnT5UCEdyPz3ai9hQ==} + + character-reference-invalid@2.0.1: + resolution: {integrity: sha512-iBZ4F4wRbyORVsu0jPV7gXkOsGYjGHPmAyv+HiHG8gi5PtC9KI2j1+v8/tlibRvjoWX027ypmG/n0HtO5t7unw==} + chardet@0.7.0: resolution: {integrity: sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA==} @@ -3122,6 +3214,10 @@ packages: resolution: {integrity: sha512-NIxF55hv4nSqQswkAeiOi1r83xy8JldOFDTWiug55KBu9Jnblncd2U6ViHmYgHf01TPZS77NJBhBMKdWj9HQMQ==} engines: {node: '>=8'} + ci-info@4.3.1: + resolution: {integrity: sha512-Wdy2Igu8OcBpI2pZePZ5oWjPC38tmDVx5WKUXKwlLYkA0ozo85sLsLvkBbBn/sZaSCMFOGZJ14fvW9t5/d7kdA==} + engines: {node: '>=8'} + cjs-module-lexer@1.4.3: resolution: {integrity: sha512-9z8TZaGM1pfswYeXrUpzPrkx8UnWYdhJclsiYMm6x/w5+nN+8Tf/LnAgfLGQCm59qAOxU8WwHEq2vNwF6i4j+Q==} @@ -3164,6 +3260,9 @@ packages: resolution: {integrity: sha512-QVb0dM5HvG+uaxitm8wONl7jltx8dqhfU33DcqtOZcLSVIKSDDLDi7+0LbAKiyI8hD9u42m2YxXSkMGWThaecQ==} engines: {iojs: '>= 1.0.0', node: '>= 0.12.0'} + collapse-white-space@2.1.0: + resolution: {integrity: sha512-loKTxY1zCOuG4j9f6EPnuyyYkf58RnhhWTvRoZEokgB+WbdXehfjFviyOVYkqzEWz1Q5kRiZdBYS5SwxbQYwzw==} + collect-v8-coverage@1.0.3: resolution: {integrity: sha512-1L5aqIkwPfiodaMgQunkF1zRhNqifHBmtbbbxcr6yVxxBnliw4TDOW6NxpO8DJLgJ16OT+Y4ztZqP6p/FtXnAw==} @@ -3190,6 +3289,9 @@ packages: resolution: {integrity: sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==} engines: {node: '>= 0.8'} + comma-separated-tokens@2.0.3: + resolution: {integrity: sha512-Fu4hJdvzeylCfQPp9SGWidpzrMs7tTrlu6Vb8XGaRGck8QSNZJJp538Wrb60Lax4fPwR64ViY468OIUTbRlGZg==} + commander@10.0.1: resolution: {integrity: sha512-y4Mg2tXshplEbSGzx7amzPwKKOCGuoSRP/CjEdwwk0FOGlUbq6lKuoyDZTNZkmxHdJtp54hdfY/JUrdL7Xfdug==} engines: {node: '>=14'} @@ -3235,6 +3337,10 @@ packages: resolution: {integrity: sha512-27HBghJxjiZtIk3Ycvn/4kbJk/1uZuJFfuPEns6LaEvpvG1f0hTea8lilrouyo9mVc2GWdcEZ8OLoGmSADlrCw==} engines: {'0': node >= 0.8} + concat-stream@2.0.0: + resolution: {integrity: sha512-MWufYdFw53ccGjCA+Ol7XJYpAlW6/prSMzuPOTRnJGcGzuhLn4Scrz7qf6o8bROZ514ltazcIFJZevcfbo0x7A==} + engines: {'0': node >= 6.0} + configstore@7.0.0: resolution: {integrity: sha512-yk7/5PN5im4qwz0WFZW3PXnzHgPu9mX29Y8uZ3aefe2lBPC1FYttWZRcaW9fKkT0pBCJyuQ2HfbmPVaODi9jcQ==} engines: {node: '>=18'} @@ -3485,6 +3591,9 @@ packages: decimal.js@10.6.0: resolution: {integrity: sha512-YpgQiITW3JXGntzdUmyUR1V812Hn8T1YVXhCu+wO3OpS4eU9l4YdD3qjyiKdV6mvV29zapkMeD390UVEf2lkUg==} + decode-named-character-reference@1.2.0: + resolution: {integrity: sha512-c6fcElNV6ShtZXmsgNgFFV5tVX2PaV4g+MOAkb8eXHvn6sryJBrZa9r0zV6+dtTyoCKxtDy5tyQ5ZwQuidtd+Q==} + decompress-response@6.0.0: resolution: {integrity: sha512-aW35yZM6Bb/4oJlZncMH2LCoZtJXTRxES17vE3hoRiowU2kWHaJKFkSBDnDR+cm9J+9QhXmREyIfv0pji9ejCQ==} engines: {node: '>=10'} @@ -3555,6 +3664,10 @@ packages: resolution: {integrity: sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==} engines: {node: '>= 0.8'} + dequal@2.0.3: + resolution: {integrity: sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==} + engines: {node: '>=6'} + destroy@1.2.0: resolution: {integrity: sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==} engines: {node: '>= 0.8', npm: 1.2.8000 || >= 1.4.16} @@ -3575,6 +3688,9 @@ packages: detect-node@2.1.0: resolution: {integrity: sha512-T0NIuQpnTvFDATNuHN5roPwSBG83rFsuO+MXXH9/3N1eFbn4wcPjttvjMLEPWJ0RGUYgQE7cGgS3tNxbqCGM7g==} + devlop@1.1.0: + resolution: {integrity: sha512-RWmIqhcFf1lRYBvNmr7qTNuyCt/7/ns2jbpp1+PalgE/rDQcBT0fioSMUpJ93irlUhC5hrg4cYqe6U+0ImW0rA==} + devtools-protocol@0.0.1367902: resolution: {integrity: sha512-XxtPuC3PGakY6PD7dG66/o8KwJ/LkH2/EKe19Dcw58w53dv4/vSQEkn/SzuyhHE2q4zPgCkxQBxus3VV4ql+Pg==} @@ -3674,6 +3790,9 @@ packages: resolution: {integrity: sha512-DeWwawk6r5yR9jFgnDKYt4sLS0LmHJJi3ZOnb5/JdbYwj3nW+FxQnHIjhBKz8YLC7oRNPVM9NQ47I3CVx34eqQ==} engines: {node: '>=12'} + emoji-regex@10.6.0: + resolution: {integrity: sha512-toUI84YS5YmxW219erniWD0CIVOo46xGKColeNQRgOzDorgBi1v4D71/OFzgD9GO2UGKIv1C3Sp8DAn0+j5w7A==} + emoji-regex@8.0.0: resolution: {integrity: sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==} @@ -3723,6 +3842,9 @@ packages: engines: {node: '>=4'} hasBin: true + err-code@2.0.3: + resolution: {integrity: sha512-2bmlRpNKBxT/CRmPOlyISQpNj+qSeYvcym/uT0Jx2bMOlKLtSy1ZmLuVxSEKKyor/N5yhvp/ZiG1oE3DEYMSFA==} + error-ex@1.3.4: resolution: {integrity: sha512-sqQamAnR14VgCr1A618A3sGrygcpK+HEbenA/HiEAkkUwcZIIB/tgWqHFxWgOyDh4nB4JCRimh79dR5Ywc9MDQ==} @@ -3783,6 +3905,10 @@ packages: resolution: {integrity: sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==} engines: {node: '>=10'} + escape-string-regexp@5.0.0: + resolution: {integrity: sha512-/veY75JbMK4j1yjvuUxuVsiS/hr/4iHs9FTT6cgTexxdE0Ly/glccBAkloH/DofkjRbZU3bnoj38mOmhkZ0lHw==} + engines: {node: '>=12'} + escodegen@2.1.0: resolution: {integrity: sha512-2NlIDTwUWJN0mRPQOdtQBzbUHvdGY2P1VXSyU83Q3xKxM7WHX2Ql8dKq782Q9TgQUNOLEzEYu9bzLNj1q88I5w==} engines: {node: '>=6.0'} @@ -3976,6 +4102,9 @@ packages: resolution: {integrity: sha512-28HqgMZAmih1Czt9ny7qr6ek2qddF4FclbMzwhCREB6OFfH+rXAnuNCwo1/wFvrtbgsQDb4kSbX9de9lFbrXnA==} engines: {node: '>= 0.10.0'} + extend@3.0.2: + resolution: {integrity: sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==} + extendable-error@0.1.7: resolution: {integrity: sha512-UOiS2in6/Q0FK0R0q6UY9vYpQ21mr/Qn1KOnte7vsACuNJf514WvCCUHSRCPcgjPT2bAhNIJdlE6bVap1GKmeg==} @@ -4021,6 +4150,9 @@ packages: fastq@1.19.1: resolution: {integrity: sha512-GwLTyxkCXjXbxqIhTsMI2Nui8huMPtnxg7krajPJAjnEG/iiOS7i+zCtWGZR9G0NBKbXKh6X9m9UIsYX/N6vvQ==} + fault@2.0.1: + resolution: {integrity: sha512-WtySTkS4OKev5JtpHXnib4Gxiurzh5NCGvWrFaZ34m6JehfTUhKZvn9njTfw48t6JumVQOmrKqpmGcdwxnhqBQ==} + faye-websocket@0.11.4: resolution: {integrity: sha512-CzbClwlXAuiRQAlUyfqPgvPoNKTckTPGfwZV4ZdAhVcP2lh9KUxJg2b5GkE7XbjKQ3YJnQ9z6D9ntLAlB+tP8g==} engines: {node: '>=0.8.0'} @@ -4136,6 +4268,10 @@ packages: resolution: {integrity: sha512-KrGhL9Q4zjj0kiUt5OO4Mr/A/jlI2jDYs5eHBpYHPcBEVSiipAvn2Ko2HnPe20rmcuuvMHNdZFp+4IlGTMF0Ow==} engines: {node: '>= 6'} + format@0.2.2: + resolution: {integrity: sha512-wzsgA6WOq+09wrU1tsJ09udeR/YZRaeArL9e1wPbFg3GG2yDnC2ldKpxs4xunpFF9DgqCqOIra3bc1HWrJ37Ww==} + engines: {node: '>=0.4.x'} + forwarded-parse@2.1.2: resolution: {integrity: sha512-alTFZZQDKMporBH77856pXgzhEzaUVmLCDk+egLgIgHst3Tpndzz8MnKe+GzRJRfvVdn69HhpW7cmXzvtLvJAw==} @@ -4362,6 +4498,10 @@ packages: resolution: {integrity: sha512-kyCuEOWjJqZuDbRHzL8V93NzQhwIB71oFWSyzVo+KPZI+pnQPPxucdkrOZvkLRnrf5URsQM+IJ09Dw29cRALIA==} engines: {node: '>=10'} + hosted-git-info@7.0.2: + resolution: {integrity: sha512-puUZAUKT5m8Zzvs72XWy3HtvVbTWljRE66cP60bxJzAqf2DgICo7lYTY2IHUmLnNpjYvw5bvmoHvPc0QO2a62w==} + engines: {node: ^16.14.0 || >=18.0.0} + hpack.js@2.1.6: resolution: {integrity: sha512-zJxVehUdMGIKsRaNt7apO2Gqp0BdqW5yaiGHXXmbpvxgBYVZnAql+BJb4RO5ad2MgpbZKn5G6nMnegrH1FcNYQ==} @@ -4478,6 +4618,10 @@ packages: resolution: {integrity: sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==} engines: {node: '>= 4'} + ignore@6.0.2: + resolution: {integrity: sha512-InwqeHHN2XpumIkMvpl/DCJVrAHgCsG5+cn1XlnLWGwtZBm8QJfSusItfrwx81CTp5agNZqpKU2J/ccC5nGT4A==} + engines: {node: '>= 4'} + ignore@7.0.5: resolution: {integrity: sha512-Hs59xBNfUIunMFgWAbGX5cq6893IbWg4KnrjbYwX3tx0ztorVgTDA6B2sxf8ejHJ4wz8BqGUMYlnzNBer5NvGg==} engines: {node: '>= 4'} @@ -4506,6 +4650,9 @@ packages: engines: {node: '>=8'} hasBin: true + import-meta-resolve@4.2.0: + resolution: {integrity: sha512-Iqv2fzaTQN28s/FwZAoFq0ZSs/7hMAHJVX+w8PZl3cY19Pxk6jFFalxQoIfW2826i/fDLXv8IiEZRIT0lDuWcg==} + imurmurhash@0.1.4: resolution: {integrity: sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==} engines: {node: '>=0.8.19'} @@ -4531,6 +4678,10 @@ packages: resolution: {integrity: sha512-it4HyVAUTKBc6m8e1iXWvXSTdndF7HbdN713+kvLrymxTaU4AUBWrJ4vEooP+V7fexnVD3LKcBshjGGPefSMUQ==} engines: {node: ^12.13.0 || ^14.15.0 || >=16.0.0} + ini@4.1.3: + resolution: {integrity: sha512-X7rqawQBvfdjS10YU1y1YVreA3SsLrW9dX2CewP2EbBJM4ypVNLDkO5y04gejPwKIY9lR+7r9gn3rFPt/kmWFg==} + engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0} + inquirer@7.3.3: resolution: {integrity: sha512-JG3eIAj5V9CwcGvuOmoo6LB9kbAYT8HXffUl6memuszlwDC/qvFAJw49XJ5NROSFNPxp3iQg1GqkFhaY/CR0IA==} engines: {node: '>=8.0.0'} @@ -4565,6 +4716,12 @@ packages: resolution: {integrity: sha512-1ANGLZ+Nkv1ptFb2pa8oG8Lem4krflKuX/gINiHJHjJUKaJHk/SXk5x6K3J+39/p0h1RQ2saROclJJ+QLvETCQ==} engines: {node: '>=8'} + is-alphabetical@2.0.1: + resolution: {integrity: sha512-FWyyY60MeTNyeSRpkM2Iry0G9hpr7/9kD40mD/cGQEuilcZYS4okz8SN2Q6rLCJ8gbCt6fN+rC+6tMGS99LaxQ==} + + is-alphanumerical@2.0.1: + resolution: {integrity: sha512-hmbYhX/9MUMF5uh7tOXyK/n0ZvWpad5caBA17GsC6vyuCqaWliRG5K1qS9inmUhEMaOBIW7/whAnSwveW/LtZw==} + is-array-buffer@3.0.5: resolution: {integrity: sha512-DDfANUiiG2wC1qawP66qlTugJeL5HyzMpfr8lLK+jMQirGzNod0B12cFB/9q838Ru27sBwfw78/rdoU7RERz6A==} engines: {node: '>= 0.4'} @@ -4611,6 +4768,9 @@ packages: resolution: {integrity: sha512-PwwhEakHVKTdRNVOw+/Gyh0+MzlCl4R6qKvkhuvLtPMggI1WAHt9sOwZxQLSGpUaDnrdyDsomoRgNnCfKNSXXg==} engines: {node: '>= 0.4'} + is-decimal@2.0.1: + resolution: {integrity: sha512-AAB9hiomQs5DXWcRB1rqsxGUstbRroFOPPVAomNk/3XHR5JyEZChOyTWe2oayKnsSsr/kcGqF+z6yuH6HHpN0A==} + is-docker@2.2.1: resolution: {integrity: sha512-F+i2BKsFrH66iaUFc0woD8sLy8getkwTwtOBjvs56Cx4CgJDeKQeqfz8wAYiSb8JOprWhHH5p77PbmYCvvUuXQ==} engines: {node: '>=8'} @@ -4621,6 +4781,9 @@ packages: engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} hasBin: true + is-empty@1.2.0: + resolution: {integrity: sha512-F2FnH/otLNJv0J6wc73A5Xo7oHLNnqplYqZhUu01tD54DIPvxIRSTSLkrUB/M0nHO4vo1O9PDfN4KoTxCzLh/w==} + is-extendable@0.1.1: resolution: {integrity: sha512-5BMULNob1vgFX6EjQw5izWDxrecWK9AM72rugNr0TFldMOi0fj6Jk+zeKIt0xGj4cEfQIJth4w3OKWOJ4f+AFw==} engines: {node: '>=0.10.0'} @@ -4649,6 +4812,9 @@ packages: resolution: {integrity: sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==} engines: {node: '>=0.10.0'} + is-hexadecimal@2.0.1: + resolution: {integrity: sha512-DgZQp241c8oO6cA1SbTEWiXeoxV42vlcJxgH+B3hi1AiqqKruZR3ZGF8In3fj4+/y/7rHvlOZLZtgJ/4ttYGZg==} + is-inside-container@1.0.0: resolution: {integrity: sha512-KIYLCCJghfHZxqjYBE7rEy0OBuTd5xCHS7tHVgvCLkx7StIoaxwNW3hCALgEUjFfeRk+MG/Qxmp/vtETEF3tRA==} engines: {node: '>=14.16'} @@ -4690,6 +4856,10 @@ packages: resolution: {integrity: sha512-gwsOE28k+23GP1B6vFl1oVh/WOzmawBrKwo5Ev6wMKzPkaXaCDIQKzLnvsA42DRlbVTWorkgTKIviAKCWkfUwA==} engines: {node: '>=10'} + is-plain-obj@4.1.0: + resolution: {integrity: sha512-+Pgi+vMuUNkJyExiMBt5IlFoMyKnr5zhJ4Uspz58WOhBF5QoIZkFyNHIbBAtHwzVAgk5RtndVNsDRN61/mmDqg==} + engines: {node: '>=12'} + is-plain-object@2.0.4: resolution: {integrity: sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==} engines: {node: '>=0.10.0'} @@ -4774,6 +4944,10 @@ packages: isexe@2.0.0: resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==} + isexe@3.1.1: + resolution: {integrity: sha512-LpB/54B+/2J5hqQ7imZHfdU31OlgQqx7ZicVlkm9kzg9/w8GKLEcFfJl/t7DCEDueOyBAD6zCCwTO6Fzs0NoEQ==} + engines: {node: '>=16'} + isobject@3.0.1: resolution: {integrity: sha512-WhB9zCku7EGTj/HQQRz5aUQEUeoQZH2bWcltRErOpymJ4boYE6wL9Tbr23krRPSZ+C5zqNSrSw+Cc7sZZ4b7vg==} engines: {node: '>=0.10.0'} @@ -5006,6 +5180,10 @@ packages: json-parse-even-better-errors@2.3.1: resolution: {integrity: sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==} + json-parse-even-better-errors@3.0.2: + resolution: {integrity: sha512-fi0NG4bPjCHunUJffmLd0gxssIgkNmArMvis4iNah6Owg1MCJjWhEcDLmsK6iGkJq3tHwbDkTlce70/tmXN4cQ==} + engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0} + json-schema-traverse@0.4.1: resolution: {integrity: sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==} @@ -5130,9 +5308,16 @@ packages: lines-and-columns@1.2.4: resolution: {integrity: sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==} + lines-and-columns@2.0.4: + resolution: {integrity: sha512-wM1+Z03eypVAVUCE7QdSqpVIvelbOakn1M0bPDoA4SGWPx3sNDVUiMo3L6To6WWGClB7VyXnhQ4Sn7gxiJbE6A==} + engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + linkify-it@3.0.3: resolution: {integrity: sha512-ynTsyrFSdE5oZ/O9GEf00kPngmOfVwazR5GKDq6EYfhlpFug3J2zybX56a2PRRpc9P+FuSoGNAwjlbDs9jJBPQ==} + load-plugin@6.0.3: + resolution: {integrity: sha512-kc0X2FEUZr145odl68frm+lMJuQ23+rTXYmR6TImqPtbpmXC4vVXbWKDQ9IzndA0HfyQamWfKLhzsqGSTxE63w==} + loader-runner@4.3.0: resolution: {integrity: sha512-3R/1M+yS3j5ou80Me59j7F9IMs4PXs3VqRrm0TU3AbKPxlmpoY1TNscJV/oGJXo8qCatFGTfDbY6W6ipGOYXfg==} engines: {node: '>=6.11.5'} @@ -5193,6 +5378,9 @@ packages: resolution: {integrity: sha512-HgMmCqIJSAKqo68l0rS2AanEWfkxaZ5wNiEFb5ggm08lDs9Xl2KxBlX3PTcaD2chBM1gXAYf491/M2Rv8Jwayg==} engines: {node: '>= 0.6.0'} + longest-streak@3.1.0: + resolution: {integrity: sha512-9Ri+o0JYgehTaVBBDoMqIl8GXtbWg711O3srftcHhZ0dqnETqLaoIK0x17fUw9rFSlK/0NlsKe0Ahhyl5pXE2g==} + lookup-closest-locale@6.2.0: resolution: {integrity: sha512-/c2kL+Vnp1jnV6K6RpDTHK3dgg0Tu2VVp+elEiJpjfS1UyY7AjOYHohRug6wT0OpoX2qFgNORndE9RqesfVxWQ==} @@ -5239,10 +5427,17 @@ packages: map-values@1.0.1: resolution: {integrity: sha512-BbShUnr5OartXJe1GeccAWtfro11hhgNJg6G9/UtWKjVGvV5U4C09cg5nk8JUevhXODaXY+hQ3xxMUKSs62ONQ==} + markdown-extensions@2.0.0: + resolution: {integrity: sha512-o5vL7aDWatOTX8LzaS1WMoaoxIiLRQJuIKKe2wAw6IeULDHaqbiqiggmx+pKvZDb1Sj+pE46Sn1T7lCqfFtg1Q==} + engines: {node: '>=16'} + markdown-it@12.3.2: resolution: {integrity: sha512-TchMembfxfNVpHkbtriWltGWc+m3xszaRD0CZup7GFFhzIgQqxIfn3eGj1yZpfuflzPvfkt611B2Q/Bsk1YnGg==} hasBin: true + markdown-table@3.0.4: + resolution: {integrity: sha512-wiYz4+JrLyb/DqW2hkFJxP7Vd7JuTDm77fvbM8VfEQdmSMqcImWeeRbHwZjBjIFki/VaMK2BhFi7oUUZeM5bqw==} + markdownlint-cli@0.31.1: resolution: {integrity: sha512-keIOMwQn+Ch7MoBwA+TdkyVMuxAeZFEGmIIlvwgV0Z1TGS5MxPnRr29XCLhkNzCHU+uNKGjU+VEjLX+Z9kli6g==} engines: {node: '>=12'} @@ -5265,6 +5460,51 @@ packages: mathml-tag-names@2.1.3: resolution: {integrity: sha512-APMBEanjybaPzUrfqU0IMU5I0AswKMH7k8OTLs0vvV4KZpExkTkY87nR/zpbuTPj+gARop7aGUbl11pnDfW6xg==} + mdast-comment-marker@3.0.0: + resolution: {integrity: sha512-bt08sLmTNg00/UtVDiqZKocxqvQqqyQZAg1uaRuO/4ysXV5motg7RolF5o5yy/sY1rG0v2XgZEqFWho1+2UquA==} + + mdast-util-directive@3.1.0: + resolution: {integrity: sha512-I3fNFt+DHmpWCYAT7quoM6lHf9wuqtI+oCOfvILnoicNIqjh5E3dEJWiXuYME2gNe8vl1iMQwyUHa7bgFmak6Q==} + + mdast-util-find-and-replace@3.0.2: + resolution: {integrity: sha512-Tmd1Vg/m3Xz43afeNxDIhWRtFZgM2VLyaf4vSTYwudTyeuTneoL3qtWMA5jeLyz/O1vDJmmV4QuScFCA2tBPwg==} + + mdast-util-from-markdown@2.0.2: + resolution: {integrity: sha512-uZhTV/8NBuw0WHkPTrCqDOl0zVe1BIng5ZtHoDk49ME1qqcjYmmLmOf0gELgcRMxN4w2iuIeVso5/6QymSrgmA==} + + mdast-util-frontmatter@2.0.1: + resolution: {integrity: sha512-LRqI9+wdgC25P0URIJY9vwocIzCcksduHQ9OF2joxQoyTNVduwLAFUzjoopuRJbJAReaKrNQKAZKL3uCMugWJA==} + + mdast-util-gfm-autolink-literal@2.0.1: + resolution: {integrity: sha512-5HVP2MKaP6L+G6YaxPNjuL0BPrq9orG3TsrZ9YXbA3vDw/ACI4MEsnoDpn6ZNm7GnZgtAcONJyPhOP8tNJQavQ==} + + mdast-util-gfm-footnote@2.1.0: + resolution: {integrity: sha512-sqpDWlsHn7Ac9GNZQMeUzPQSMzR6Wv0WKRNvQRg0KqHh02fpTz69Qc1QSseNX29bhz1ROIyNyxExfawVKTm1GQ==} + + mdast-util-gfm-strikethrough@2.0.0: + resolution: {integrity: sha512-mKKb915TF+OC5ptj5bJ7WFRPdYtuHv0yTRxK2tJvi+BDqbkiG7h7u/9SI89nRAYcmap2xHQL9D+QG/6wSrTtXg==} + + mdast-util-gfm-table@2.0.0: + resolution: {integrity: sha512-78UEvebzz/rJIxLvE7ZtDd/vIQ0RHv+3Mh5DR96p7cS7HsBhYIICDBCu8csTNWNO6tBWfqXPWekRuj2FNOGOZg==} + + mdast-util-gfm-task-list-item@2.0.0: + resolution: {integrity: sha512-IrtvNvjxC1o06taBAVJznEnkiHxLFTzgonUdy8hzFVeDun0uTjxxrRGVaNFqkU1wJR3RBPEfsxmU6jDWPofrTQ==} + + mdast-util-gfm@3.1.0: + resolution: {integrity: sha512-0ulfdQOM3ysHhCJ1p06l0b0VKlhU0wuQs3thxZQagjcjPrlFRqY215uZGHHJan9GEAXd9MbfPjFJz+qMkVR6zQ==} + + mdast-util-mdx-expression@2.0.1: + resolution: {integrity: sha512-J6f+9hUp+ldTZqKRSg7Vw5V6MqjATc+3E4gf3CFNcuZNWD8XdyI6zQ8GqH7f8169MM6P7hMBRDVGnn7oHB9kXQ==} + + mdast-util-phrasing@4.1.0: + resolution: {integrity: sha512-TqICwyvJJpBwvGAMZjj4J2n0X8QWp21b9l0o7eXyVJ25YNWYbJDVIyD1bZXE6WtV6RmKJVYmQAKWa0zWOABz2w==} + + mdast-util-to-markdown@2.1.2: + resolution: {integrity: sha512-xj68wMTvGXVOKonmog6LwyJKrYXZPvlwabaryTjLh9LuvovB/KAH+kvi8Gjj+7rJjsFi23nkUxRQv1KqSroMqA==} + + mdast-util-to-string@4.0.0: + resolution: {integrity: sha512-0H44vDimn51F0YwvxSJSm0eCDOJTRlmN0R1yBh4HLj9wiV1Dn0QoXGbvFAWj2hSItVTlCmBF1hqKlIyUBVFLPg==} + mdn-data@2.0.28: resolution: {integrity: sha512-aylIc7Z9y4yzHYAJNuESG3hfhC+0Ibp/MAMiaOZgNv4pmEdFyfZhhhny4MNiAfWdBQ1RQ2mfDWmM1x8SvGyp8g==} @@ -5316,6 +5556,93 @@ packages: resolution: {integrity: sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w==} engines: {node: '>= 0.6'} + micromark-core-commonmark@2.0.3: + resolution: {integrity: sha512-RDBrHEMSxVFLg6xvnXmb1Ayr2WzLAWjeSATAoxwKYJV94TeNavgoIdA0a9ytzDSVzBy2YKFK+emCPOEibLeCrg==} + + micromark-extension-frontmatter@2.0.0: + resolution: {integrity: sha512-C4AkuM3dA58cgZha7zVnuVxBhDsbttIMiytjgsM2XbHAB2faRVaHRle40558FBN+DJcrLNCoqG5mlrpdU4cRtg==} + + micromark-extension-gfm-autolink-literal@2.1.0: + resolution: {integrity: sha512-oOg7knzhicgQ3t4QCjCWgTmfNhvQbDDnJeVu9v81r7NltNCVmhPy1fJRX27pISafdjL+SVc4d3l48Gb6pbRypw==} + + micromark-extension-gfm-footnote@2.1.0: + resolution: {integrity: sha512-/yPhxI1ntnDNsiHtzLKYnE3vf9JZ6cAisqVDauhp4CEHxlb4uoOTxOCJ+9s51bIB8U1N1FJ1RXOKTIlD5B/gqw==} + + micromark-extension-gfm-strikethrough@2.1.0: + resolution: {integrity: sha512-ADVjpOOkjz1hhkZLlBiYA9cR2Anf8F4HqZUO6e5eDcPQd0Txw5fxLzzxnEkSkfnD0wziSGiv7sYhk/ktvbf1uw==} + + micromark-extension-gfm-table@2.1.1: + resolution: {integrity: sha512-t2OU/dXXioARrC6yWfJ4hqB7rct14e8f7m0cbI5hUmDyyIlwv5vEtooptH8INkbLzOatzKuVbQmAYcbWoyz6Dg==} + + micromark-extension-gfm-tagfilter@2.0.0: + resolution: {integrity: sha512-xHlTOmuCSotIA8TW1mDIM6X2O1SiX5P9IuDtqGonFhEK0qgRI4yeC6vMxEV2dgyr2TiD+2PQ10o+cOhdVAcwfg==} + + micromark-extension-gfm-task-list-item@2.1.0: + resolution: {integrity: sha512-qIBZhqxqI6fjLDYFTBIa4eivDMnP+OZqsNwmQ3xNLE4Cxwc+zfQEfbs6tzAo2Hjq+bh6q5F+Z8/cksrLFYWQQw==} + + micromark-extension-gfm@3.0.0: + resolution: {integrity: sha512-vsKArQsicm7t0z2GugkCKtZehqUm31oeGBV/KVSorWSy8ZlNAv7ytjFhvaryUiCUJYqs+NoE6AFhpQvBTM6Q4w==} + + micromark-factory-destination@2.0.1: + resolution: {integrity: sha512-Xe6rDdJlkmbFRExpTOmRj9N3MaWmbAgdpSrBQvCFqhezUn4AHqJHbaEnfbVYYiexVSs//tqOdY/DxhjdCiJnIA==} + + micromark-factory-label@2.0.1: + resolution: {integrity: sha512-VFMekyQExqIW7xIChcXn4ok29YE3rnuyveW3wZQWWqF4Nv9Wk5rgJ99KzPvHjkmPXF93FXIbBp6YdW3t71/7Vg==} + + micromark-factory-space@2.0.1: + resolution: {integrity: sha512-zRkxjtBxxLd2Sc0d+fbnEunsTj46SWXgXciZmHq0kDYGnck/ZSGj9/wULTV95uoeYiK5hRXP2mJ98Uo4cq/LQg==} + + micromark-factory-title@2.0.1: + resolution: {integrity: sha512-5bZ+3CjhAd9eChYTHsjy6TGxpOFSKgKKJPJxr293jTbfry2KDoWkhBb6TcPVB4NmzaPhMs1Frm9AZH7OD4Cjzw==} + + micromark-factory-whitespace@2.0.1: + resolution: {integrity: sha512-Ob0nuZ3PKt/n0hORHyvoD9uZhr+Za8sFoP+OnMcnWK5lngSzALgQYKMr9RJVOWLqQYuyn6ulqGWSXdwf6F80lQ==} + + micromark-util-character@2.1.1: + resolution: {integrity: sha512-wv8tdUTJ3thSFFFJKtpYKOYiGP2+v96Hvk4Tu8KpCAsTMs6yi+nVmGh1syvSCsaxz45J6Jbw+9DD6g97+NV67Q==} + + micromark-util-chunked@2.0.1: + resolution: {integrity: sha512-QUNFEOPELfmvv+4xiNg2sRYeS/P84pTW0TCgP5zc9FpXetHY0ab7SxKyAQCNCc1eK0459uoLI1y5oO5Vc1dbhA==} + + micromark-util-classify-character@2.0.1: + resolution: {integrity: sha512-K0kHzM6afW/MbeWYWLjoHQv1sgg2Q9EccHEDzSkxiP/EaagNzCm7T/WMKZ3rjMbvIpvBiZgwR3dKMygtA4mG1Q==} + + micromark-util-combine-extensions@2.0.1: + resolution: {integrity: sha512-OnAnH8Ujmy59JcyZw8JSbK9cGpdVY44NKgSM7E9Eh7DiLS2E9RNQf0dONaGDzEG9yjEl5hcqeIsj4hfRkLH/Bg==} + + micromark-util-decode-numeric-character-reference@2.0.2: + resolution: {integrity: sha512-ccUbYk6CwVdkmCQMyr64dXz42EfHGkPQlBj5p7YVGzq8I7CtjXZJrubAYezf7Rp+bjPseiROqe7G6foFd+lEuw==} + + micromark-util-decode-string@2.0.1: + resolution: {integrity: sha512-nDV/77Fj6eH1ynwscYTOsbK7rR//Uj0bZXBwJZRfaLEJ1iGBR6kIfNmlNqaqJf649EP0F3NWNdeJi03elllNUQ==} + + micromark-util-encode@2.0.1: + resolution: {integrity: sha512-c3cVx2y4KqUnwopcO9b/SCdo2O67LwJJ/UyqGfbigahfegL9myoEFoDYZgkT7f36T0bLrM9hZTAaAyH+PCAXjw==} + + micromark-util-html-tag-name@2.0.1: + resolution: {integrity: sha512-2cNEiYDhCWKI+Gs9T0Tiysk136SnR13hhO8yW6BGNyhOC4qYFnwF1nKfD3HFAIXA5c45RrIG1ub11GiXeYd1xA==} + + micromark-util-normalize-identifier@2.0.1: + resolution: {integrity: sha512-sxPqmo70LyARJs0w2UclACPUUEqltCkJ6PhKdMIDuJ3gSf/Q+/GIe3WKl0Ijb/GyH9lOpUkRAO2wp0GVkLvS9Q==} + + micromark-util-resolve-all@2.0.1: + resolution: {integrity: sha512-VdQyxFWFT2/FGJgwQnJYbe1jjQoNTS4RjglmSjTUlpUMa95Htx9NHeYW4rGDJzbjvCsl9eLjMQwGeElsqmzcHg==} + + micromark-util-sanitize-uri@2.0.1: + resolution: {integrity: sha512-9N9IomZ/YuGGZZmQec1MbgxtlgougxTodVwDzzEouPKo3qFWvymFHWcnDi2vzV1ff6kas9ucW+o3yzJK9YB1AQ==} + + micromark-util-subtokenize@2.1.0: + resolution: {integrity: sha512-XQLu552iSctvnEcgXw6+Sx75GflAPNED1qx7eBJ+wydBb2KCbRZe+NwvIEEMM83uml1+2WSXpBAcp9IUCgCYWA==} + + micromark-util-symbol@2.0.1: + resolution: {integrity: sha512-vs5t8Apaud9N28kgCrRUdEed4UJ+wWNvicHLPxCa9ENlYuAY31M0ETy5y1vA33YoNPDFTghEbnh6efaE8h4x0Q==} + + micromark-util-types@2.0.2: + resolution: {integrity: sha512-Yw0ECSpJoViF1qTU4DC6NwtC4aWGt1EkzaQB8KPPyCRR8z9TWeV0HbEFGTO+ZY1wB22zmxnJqhPyTpOVCpeHTA==} + + micromark@4.0.2: + resolution: {integrity: sha512-zpe98Q6kvavpCr1NPVSCMebCKfD7CA2NqZ+rykeNhONIJBpc1tFKt9hucLGwha3jNTNI8lHpctWJWoimVF4PfA==} + micromatch@4.0.8: resolution: {integrity: sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==} engines: {node: '>=8.6'} @@ -5486,6 +5813,11 @@ packages: node-releases@2.0.27: resolution: {integrity: sha512-nmh3lCkYZ3grZvqcCH+fjmQ7X+H0OeZgP40OierEaAptX4XofMh5kwNbWh7lBduUzCcV/8kZ+NDLCwm2iorIlA==} + nopt@7.2.1: + resolution: {integrity: sha512-taM24ViiimT/XntxbPyJQzCG+p4EKOpgD3mxFwW38mGjVUrfERQOeY4EDHjdnptttfHuHQXFx+lTP08Q+mLa/w==} + engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0} + hasBin: true + normalize-package-data@2.5.0: resolution: {integrity: sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA==} @@ -5493,6 +5825,10 @@ packages: resolution: {integrity: sha512-p2W1sgqij3zMMyRC067Dg16bfzVH+w7hyegmpIvZ4JNjqtGOVAIvLmjBx3yP7YTe9vKJgkoNOPjwQGogDoMXFA==} engines: {node: '>=10'} + normalize-package-data@6.0.2: + resolution: {integrity: sha512-V6gygoYb/5EmNI+MEGrWkC+e6+Rr7mTmfHrxDbLzxQogBkgzo76rkok0Am6thgSF7Mv2nLOajAJj5vDJZEFn7g==} + engines: {node: ^16.14.0 || >=18.0.0} + normalize-path@3.0.0: resolution: {integrity: sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==} engines: {node: '>=0.10.0'} @@ -5508,9 +5844,21 @@ packages: npm-bundled@1.1.2: resolution: {integrity: sha512-x5DHup0SuyQcmL3s7Rx/YQ8sbw/Hzg0rj48eN0dV7hf5cmQq5PXIeioroH3raV1QC1yh3uTYuMThvEQF3iKgGQ==} + npm-install-checks@6.3.0: + resolution: {integrity: sha512-W29RiK/xtpCGqn6f3ixfRYGk+zRyr+Ew9F2E20BfXxT5/euLdA/Nm7fO7OeTGuAmTs30cpgInyJ0cYe708YTZw==} + engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0} + npm-normalize-package-bin@1.0.1: resolution: {integrity: sha512-EPfafl6JL5/rU+ot6P3gRSCpPDW5VmIzX959Ob1+ySFUuuYHWHekXpwdUZcKP5C+DS4GEtdJluwBjnsNDl+fSA==} + npm-normalize-package-bin@3.0.1: + resolution: {integrity: sha512-dMxCf+zZ+3zeQZXKxmyuCKlIDPGuv8EF940xbkC4kQVDTtqoh6rJFO+JTKSA6/Rwi0getWmtuy4Itup0AMcaDQ==} + engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0} + + npm-package-arg@11.0.3: + resolution: {integrity: sha512-sHGJy8sOC1YraBywpzQlIKBE4pBbGbiF95U6Auspzyem956E0+FtDtsx1ZxlOJkQCZ1AFXAY/yuvtFYrOxF+Bw==} + engines: {node: ^16.14.0 || >=18.0.0} + npm-package-json-lint@6.4.0: resolution: {integrity: sha512-cuXAJJB1Rdqz0UO6w524matlBqDBjcNt7Ru+RDIu4y6RI1gVqiWBnylrK8sPRk81gGBA0X8hJbDXolVOoTc+sA==} engines: {node: '>=14.0.0', npm: '>=6.0.0'} @@ -5521,6 +5869,10 @@ packages: engines: {node: '>=10'} hasBin: true + npm-pick-manifest@9.1.0: + resolution: {integrity: sha512-nkc+3pIIhqHVQr085X9d2JzPzLyjzQS96zbruppqC9aZRm/x8xx6xhI98gHtsfELP2bE+loHq8ZaHFHhe+NauA==} + engines: {node: ^16.14.0 || >=18.0.0} + npm-run-path@4.0.1: resolution: {integrity: sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==} engines: {node: '>=8'} @@ -5683,10 +6035,17 @@ packages: parse-cache-control@1.0.1: resolution: {integrity: sha512-60zvsJReQPX5/QP0Kzfd/VrpjScIQ7SHBW6bFCYfEP+fp0Eppr1SHhIO5nd1PjZtvclzSzES9D/p5nFJurwfWg==} + parse-entities@4.0.2: + resolution: {integrity: sha512-GG2AQYWoLgL877gQIKeRPGO1xF9+eG1ujIb5soS5gPvLQ1y2o8FL90w2QWNdf9I361Mpp7726c+lj3U0qK1uGw==} + parse-json@5.2.0: resolution: {integrity: sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==} engines: {node: '>=8'} + parse-json@7.1.1: + resolution: {integrity: sha512-SgOTCX/EZXtZxBE5eJ97P4yGM5n37BwRU+YMsH4vNzFqJV/oWFXXCmwFlgWUM4PrakybVOueJJ6pwHqSVhTFDw==} + engines: {node: '>=16'} + parse-passwd@1.0.0: resolution: {integrity: sha512-1Y1A//QUXEZK7YKz+rD9WydcE1+EuPr6ZBgKecAB8tmoW6UFv0NREVJe1p+jRxtThkcbbKkfwIbWJe/IeE6m2Q==} engines: {node: '>=0.10.0'} @@ -5789,6 +6148,10 @@ packages: resolution: {integrity: sha512-4UGewrYgqDFw9vV6zNV+ADmPAUAfJPKtGvb/VdpQAx25X5f3xXdGdyOEVFwkl8Hl/tl7+xbeHqSEM+D5/TirUg==} engines: {node: '>=10'} + pluralize@8.0.0: + resolution: {integrity: sha512-Nc3IT5yHzflTfbjgqWcCPpo7DaKy4FnpB0l/zCAW0Tc7jxAiuqSxHasntB3D7887LSrA93kDJ9IXovxJYxyLCA==} + engines: {node: '>=4'} + possible-typed-array-names@1.1.0: resolution: {integrity: sha512-/+5VFTchJDoVj3bhoqi6UeymcD00DAwb1nJwamzPvHEszJ4FpF6SNNbUbOS8yI56qHzdV8eK0qEfOSiodkTdxg==} engines: {node: '>= 0.4'} @@ -6058,6 +6421,10 @@ packages: resolution: {integrity: sha512-Pdlw/oPxN+aXdmM9R00JVC9WVFoCLTKJvDVLgmJ+qAffBMxsV85l/Lu7sNx4zSzPyoL2euImuEwHhOXdEgNFZQ==} engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + proc-log@4.2.0: + resolution: {integrity: sha512-g8+OnU/L2v+wyiVK+D5fA34J7EH8jZ8DDlvwhRCMxmMj7UCBvxiO1mGeN+36JXIKF4zevU4kRBd8lVgG9vLelA==} + engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0} + process-nextick-args@2.0.1: resolution: {integrity: sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==} @@ -6065,6 +6432,18 @@ packages: resolution: {integrity: sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==} engines: {node: '>=0.4.0'} + promise-inflight@1.0.1: + resolution: {integrity: sha512-6zWPyEOFaQBJYcGMHBKTKJ3u6TBsnMFOIZSa6ce1e/ZrrsOlnHRHbabMjLiBYKp+n44X9eUI6VUPaukCXHuG4g==} + peerDependencies: + bluebird: '*' + peerDependenciesMeta: + bluebird: + optional: true + + promise-retry@2.0.1: + resolution: {integrity: sha512-y+WKFlBR8BGXnsNlIHFGPZmyDf3DFMoLhaflAnyZgV6rG6xu+JwesTo2Q9R6XwYmtmwAFCkAk3e35jEdoeh/3g==} + engines: {node: '>=10'} + prompts@2.4.2: resolution: {integrity: sha512-NxNv/kLguCA7p3jE8oL2aEBsrJWgAakBpgmgK6lpPWV+WuOmY6r2/zbAVnP+T8bQlA0nzHXSJSJW0Hq7ylaD2Q==} engines: {node: '>= 6'} @@ -6166,6 +6545,10 @@ packages: read-cache@1.0.0: resolution: {integrity: sha512-Owdv/Ft7IjOgm/i0xvNDZ1LrRANRfew4b2prF3OWMQLxLfu3bS8FVhCsrSCMK4lR56Y9ya+AThoTpDCTxCmpRA==} + read-package-json-fast@3.0.2: + resolution: {integrity: sha512-0J+Msgym3vrLOUB3hzQCuZHII0xkNGCtz/HJH9xZshwv9DbDwkw1KaE3gx/e2J5rpEY5rtOy6cyhKOPrkP7FZw==} + engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0} + read-pkg-up@7.0.1: resolution: {integrity: sha512-zK0TB7Xd6JpCLmlLmufqykGE+/TlOePD6qKClNW7hHDKFh/J7/7gCWGR7joEQEW1bKq3a3yUZSObOoWLFQ4ohg==} engines: {node: '>=8'} @@ -6238,6 +6621,73 @@ packages: resolution: {integrity: sha512-NZQZdC5wOE/H3UT28fVGL+ikOZcEzfMGk/c3iN9UGxzWHMa1op7274oyiUVrAG4B2EuFhus8SvkaYnhvW92p9Q==} hasBin: true + remark-cli@12.0.1: + resolution: {integrity: sha512-2NAEOACoTgo+e+YAaCTODqbrWyhMVmlUyjxNCkTrDRHHQvH6+NbrnqVvQaLH/Q8Ket3v90A43dgAJmXv8y5Tkw==} + hasBin: true + + remark-frontmatter@5.0.0: + resolution: {integrity: sha512-XTFYvNASMe5iPN0719nPrdItC9aU0ssC4v14mH1BCi1u0n1gAocqcujWUrByftZTbLhRtiKRyjYTSIOcr69UVQ==} + + remark-gfm@4.0.1: + resolution: {integrity: sha512-1quofZ2RQ9EWdeN34S79+KExV1764+wCUGop5CPL1WGdD0ocPpu91lzPGbwWMECpEpd42kJGQwzRfyov9j4yNg==} + + remark-lint-final-newline@3.0.1: + resolution: {integrity: sha512-q5diKHD6BMbzqWqgvYPOB8AJgLrMzEMBAprNXjcpKoZ/uCRqly+gxjco+qVUMtMWSd+P+KXZZEqoa7Y6QiOudw==} + + remark-lint-hard-break-spaces@4.1.1: + resolution: {integrity: sha512-AKDPDt39fvmr3yk38OKZEWJxxCOOUBE+96AsBfs+ExS5LW6oLa9041X5ahFDQHvHGzdoremEIaaElursaPEkNg==} + + remark-lint-list-item-bullet-indent@5.0.1: + resolution: {integrity: sha512-LKuTxkw5aYChzZoF3BkfaBheSCHs0T8n8dPHLQEuOLo6iC5wy98iyryz0KZ61GD8stlZgQO2KdWSdnP6vr40Iw==} + + remark-lint-list-item-indent@4.0.1: + resolution: {integrity: sha512-gJd1Q+jOAeTgmGRsdMpnRh01DUrAm0O5PCQxE8ttv1QZOV015p/qJH+B4N6QSmcUuPokHLAh9USuq05C73qpiA==} + + remark-lint-no-blockquote-without-marker@6.0.1: + resolution: {integrity: sha512-b4IOkNcG7C16HYAdKUeAhO7qPt45m+v7SeYbVrqvbSFtlD3EUBL8fgHRgLK1mdujFXDP1VguOEMx+Txv8JOT4w==} + + remark-lint-no-duplicate-definitions@4.0.1: + resolution: {integrity: sha512-Ek+A/xDkv5Nn+BXCFmf+uOrFSajCHj6CjhsHjtROgVUeEPj726yYekDBoDRA0Y3+z+U30AsJoHgf/9Jj1IFSug==} + + remark-lint-no-heading-content-indent@5.0.1: + resolution: {integrity: sha512-YIWktnZo7M9aw7PGnHdshvetSH3Y0qW+Fm143R66zsk5lLzn1XA5NEd/MtDzP8tSxxV+gcv+bDd5St1QUI4oSQ==} + + remark-lint-no-literal-urls@4.0.1: + resolution: {integrity: sha512-RhTANFkFFXE6bM+WxWcPo2TTPEfkWG3lJZU50ycW7tJJmxUzDNzRed/z80EVJIdGwFa0NntVooLUJp3xrogalQ==} + + remark-lint-no-shortcut-reference-image@4.0.1: + resolution: {integrity: sha512-hQhJ3Dr8ZWRdj7qm6+9vcPpqtGchhENA2UHOmcTraLf6dN1cFATCgY/HbTbRIN6NkG/EEClTgRC1QCokWR2Mmw==} + + remark-lint-no-shortcut-reference-link@4.0.1: + resolution: {integrity: sha512-YxciuUZc90QaJYhayGO80lS3zxEOBgwwLW1MKYB7AfUdkrLcLVlS+DFloiq0MZ7EDVXuuGUEnIzyjyLSbI5BUA==} + + remark-lint-no-undefined-references@5.0.2: + resolution: {integrity: sha512-5prkVb1tKwJwr5+kct/UjsLjvMdEDO7uClPeGfrxfAcN59+pWU8OUSYiqYmpSKWJPIdyxPRS8Oyf1HtaYvg8VQ==} + + remark-lint-no-unused-definitions@4.0.2: + resolution: {integrity: sha512-KRzPmvfq6b3LSEcAQZobAn+5eDfPTle0dPyDEywgPSc3E7MIdRZQenL9UL8iIqHQWK4FvdUD0GX8FXGqu5EuCw==} + + remark-lint-ordered-list-marker-style@4.0.1: + resolution: {integrity: sha512-vZTAbstcBPbGwJacwldGzdGmKwy5/4r29SZ9nQkME4alEl5B1ReSBlYa8t7QnTSW7+tqvA9Sg71RPadgAKWa4w==} + + remark-lint@10.0.1: + resolution: {integrity: sha512-1+PYGFziOg4pH7DDf1uMd4AR3YuO2EMnds/SdIWMPGT7CAfDRSnAmpxPsJD0Ds3IKpn97h3d5KPGf1WFOg6hXQ==} + + remark-message-control@8.0.0: + resolution: {integrity: sha512-brpzOO+jdyE/mLqvqqvbogmhGxKygjpCUCG/PwSCU43+JZQ+RM+sSzkCWBcYvgF3KIAVNIoPsvXjBkzO7EdsYQ==} + + remark-parse@11.0.0: + resolution: {integrity: sha512-FCxlKLNGknS5ba/1lmpYijMUzX2esxW5xQqjWxw2eHFfS2MSdaHVINFmhjo+qN1WhZhNimq0dZATN9pH0IDrpA==} + + remark-preset-lint-recommended@7.0.1: + resolution: {integrity: sha512-j1CY5u48PtZl872BQ40uWSQMT3R4gXKp0FUgevMu5gW7hFMtvaCiDq+BfhzeR8XKKiW9nIMZGfIMZHostz5X4g==} + + remark-stringify@11.0.0: + resolution: {integrity: sha512-1OSmLd3awB/t8qdoEOMazZkNsfVTeY4fTsgzcQFdXNq8ToTN4ZGwrMnlda4K6smTFKD+GRV6O48i6Z4iKgPPpw==} + + remark@15.0.1: + resolution: {integrity: sha512-Eht5w30ruCXgFmxVUSlNWQ9iiimq07URKeFS3hNc8cUWy1llX4KDWfyEDZRycMc+znsN9Ux5/tJ/BFdgdOwA3A==} + require-directory@2.1.1: resolution: {integrity: sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==} engines: {node: '>=0.10.0'} @@ -6304,6 +6754,10 @@ packages: resolution: {integrity: sha512-l+sSefzHpj5qimhFSE5a8nufZYAM3sBSVMAPtYkmC+4EH2anSGaEMXSD0izRQbu9nfyQ9y5JrVmp7E8oZrUjvA==} engines: {node: '>=8'} + retry@0.12.0: + resolution: {integrity: sha512-9LkiTwjUh6rT555DtE9rTX+BKByPfrMzEAtnlEtdEwr3Nkffwiihqe2bWADg+OQRjt9gl6ICdmB/ZFDCGAtSow==} + engines: {node: '>= 4'} + retry@0.13.1: resolution: {integrity: sha512-XQBQ3I8W1Cge0Seh+6gjj03LbmRFWuoszgK9ooCpwYIrhhoO80pfq4cUkU5DkknwfOfFteRwlZ56PYOGYyFWdg==} engines: {node: '>= 4'} @@ -6618,6 +7072,9 @@ packages: resolution: {integrity: sha512-i5uvt8C3ikiWeNZSVZNWcfZPItFQOsYTUAOkcUPGd8DqDy1uOUikjt5dG+uRlwyvR108Fb9DOd4GvXfT0N2/uQ==} engines: {node: '>= 12'} + space-separated-tokens@2.0.2: + resolution: {integrity: sha512-PEGlAwrG8yXGXRjW32fGbg66JAlOAwbObuqVoJpv/mRgoWDQfgH1wDPvtzWyUSNAXBGSk8h755YDbbcEy3SH2Q==} + spawnd@10.1.4: resolution: {integrity: sha512-drqHc0mKJmtMsiGMOCwzlc5eZ0RPtRvT7tQAluW2A0qUc0G7TQ8KLcn3E6K5qzkLkH2UkS3nYQiVGULvvsD9dw==} engines: {node: '>=16'} @@ -6688,6 +7145,10 @@ packages: resolution: {integrity: sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==} engines: {node: '>=12'} + string-width@6.1.0: + resolution: {integrity: sha512-k01swCJAgQmuADB0YIc+7TuatfNvTBVOoaUWJjTB9R4VJzR5vNWzf5t42ESVZFPS8xTySF7CAdV4t/aaIm3UnQ==} + engines: {node: '>=16'} + string.prototype.includes@2.0.1: resolution: {integrity: sha512-o7+c9bW6zpAdJHTtujeePODAhkuicdAryFsfVKwA+wGw89wJ4GTY484WTucM9hLtDEOpOvI+aHnzqnC5lHp4Rg==} engines: {node: '>= 0.4'} @@ -6717,6 +7178,9 @@ packages: string_decoder@1.3.0: resolution: {integrity: sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==} + stringify-entities@4.0.4: + resolution: {integrity: sha512-IwfBptatlO+QCJUo19AqvrPNqlVMpW9YEL2LIVY+Rpv2qsjCGxaDLNRgeGsQWJhfItebuJhsGSLjaBbNSQ+ieg==} + strip-ansi@6.0.1: resolution: {integrity: sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==} engines: {node: '>=8'} @@ -6811,6 +7275,10 @@ packages: resolution: {integrity: sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==} engines: {node: '>=10'} + supports-color@9.4.0: + resolution: {integrity: sha512-VL+lNrEoIXww1coLPOmiEmK/0sGigko5COxI09KzHc2VJXJsQ37UaQ+8quuxjDeA7+KnLGTWRyOXSLLR2Wb4jw==} + engines: {node: '>=12'} + supports-hyperlinks@2.3.0: resolution: {integrity: sha512-RpsAZlpWcDwOPQA22aCH4J0t7L8JmAvsCxfOSEwm7cQs3LshN36QaTkwd70DnBOXDWGssw2eUoc8CaRWT0XunA==} engines: {node: '>=8'} @@ -6973,6 +7441,9 @@ packages: resolution: {integrity: sha512-pkonvlKk8/ZuR0D5tLW8ljt5I8kmxp2XKymhepUeOdCEfKpZaktSArkLHZt76OB1ZvO9bssUsDty4SWhLvZpLg==} engines: {node: '>=0.10.0'} + trough@2.2.0: + resolution: {integrity: sha512-tmMpK00BjZiUyVyvrBK7knerNgmgvcV/KLVyuma/SC+TQN167GrMRciANTz09+k3zW8L8t60jWO1GpfkZdjTaw==} + ts-api-utils@1.4.3: resolution: {integrity: sha512-i3eMG77UTMD0hZhgRS562pv83RC6ukSAC2GMNWc+9dieh/+jDM5u5YG+NHX6VNDRHQcHwmsTHctP9LhbC3WxVw==} engines: {node: '>=16'} @@ -7093,6 +7564,39 @@ packages: resolution: {integrity: sha512-hpbDzxUY9BFwX+UeBnxv3Sh1q7HFxj48DTmXchNgRa46lO8uj3/1iEn3MiNUYTg1g9ctIqXCCERn8gYZhHC5lQ==} engines: {node: '>=4'} + unified-args@11.0.1: + resolution: {integrity: sha512-WEQghE91+0s3xPVs0YW6a5zUduNLjmANswX7YbBfksHNDGMjHxaWCql4SR7c9q0yov/XiIEdk6r/LqfPjaYGcw==} + + unified-engine@11.2.2: + resolution: {integrity: sha512-15g/gWE7qQl9tQ3nAEbMd5h9HV1EACtFs6N9xaRBZICoCwnNGbal1kOs++ICf4aiTdItZxU2s/kYWhW7htlqJg==} + + unified-lint-rule@3.0.1: + resolution: {integrity: sha512-HxIeQOmwL19DGsxHXbeyzKHBsoSCFO7UtRVUvT2v61ptw/G+GbysWcrpHdfs5jqbIFDA11MoKngIhQK0BeTVjA==} + + unified-message-control@5.0.0: + resolution: {integrity: sha512-B2cSAkpuMVVmPP90KCfKdBhm1e9KYJ+zK3x5BCa0N65zpq1Ybkc9C77+M5qwR8FWO7RF3LM5QRRPZtgjW6DUCw==} + + unified@11.0.5: + resolution: {integrity: sha512-xKvGhPWw3k84Qjh8bI3ZeJjqnyadK+GEFtazSfZv/rKeTkTjOJho6mFqh2SM96iIcZokxiOpg78GazTSg8+KHA==} + + unist-util-inspect@8.1.0: + resolution: {integrity: sha512-mOlg8Mp33pR0eeFpo5d2902ojqFFOKMMG2hF8bmH7ZlhnmjFgh0NI3/ZDwdaBJNbvrS7LZFVrBVtIE9KZ9s7vQ==} + + unist-util-is@6.0.1: + resolution: {integrity: sha512-LsiILbtBETkDz8I9p1dQ0uyRUWuaQzd/cuEeS1hoRSyW5E5XGmTzlwY1OrNzzakGowI9Dr/I8HVaw4hTtnxy8g==} + + unist-util-position@5.0.0: + resolution: {integrity: sha512-fucsC7HjXvkB5R3kTCO7kUjRdrS0BJt3M/FPxmHMBOm8JQi2BsHAHFsy27E0EolP8rp0NzXsJ+jNPyDWvOJZPA==} + + unist-util-stringify-position@4.0.0: + resolution: {integrity: sha512-0ASV06AAoKCDkS2+xw5RXJywruurpbC4JZSm7nr7MOt1ojAzvyyaO+UxZf18j8FCF6kmzCZKcAgN/yu2gm2XgQ==} + + unist-util-visit-parents@6.0.2: + resolution: {integrity: sha512-goh1s1TBrqSqukSc8wrjwWhL0hiJxgA8m4kFxGlQ+8FYQ3C/m11FcTs4YYem7V664AhHVvgoQLk890Ssdsr2IQ==} + + unist-util-visit@5.0.0: + resolution: {integrity: sha512-MR04uvD+07cwl/yhVuVWAtw+3GOR/knlL55Nd/wAdblk27GCVt3lqpTivy/tkJcZoNPzTwS1Y+KMojlLDhoTzg==} + universalify@0.1.2: resolution: {integrity: sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==} engines: {node: '>= 4.0.0'} @@ -7165,6 +7669,24 @@ packages: resolution: {integrity: sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==} engines: {node: '>= 0.8'} + vfile-location@5.0.3: + resolution: {integrity: sha512-5yXvWDEgqeiYiBe1lbxYF7UMAIm/IcopxMHrMQDq3nvKcjPKIhZklUKL+AE7J7uApI4kwe2snsK+eI6UTj9EHg==} + + vfile-message@4.0.3: + resolution: {integrity: sha512-QTHzsGd1EhbZs4AsQ20JX1rC3cOlt/IWJruk893DfLRr57lcnOeMaWG4K0JrRta4mIJZKth2Au3mM3u03/JWKw==} + + vfile-reporter@8.1.1: + resolution: {integrity: sha512-qxRZcnFSQt6pWKn3PAk81yLK2rO2i7CDXpy8v8ZquiEOMLSnPw6BMSi9Y1sUCwGGl7a9b3CJT1CKpnRF7pp66g==} + + vfile-sort@4.0.0: + resolution: {integrity: sha512-lffPI1JrbHDTToJwcq0rl6rBmkjQmMuXkAxsZPRS9DXbaJQvc642eCg6EGxcX2i1L+esbuhq+2l9tBll5v8AeQ==} + + vfile-statistics@3.0.0: + resolution: {integrity: sha512-/qlwqwWBWFOmpXujL/20P+Iuydil0rZZNglR+VNm6J0gpLHwuVM5s7g2TfVoswbXjZ4HuIhLMySEyIw5i7/D8w==} + + vfile@6.0.3: + resolution: {integrity: sha512-KzIbH/9tXat2u30jf+smMwFCsno4wHVdNmzFyL+T/L3UGqqk6JKfVqOFOZEpZSHADH1k40ab6NUIXZq422ov3Q==} + w3c-xmlserializer@4.0.0: resolution: {integrity: sha512-d+BFHzbiCx6zGfz0HyQ6Rg69w9k19nviJspaj4yNscGjrHu94sVP+aRm75yEbCh+r2/yR+7q6hux9LVtbuTGBw==} engines: {node: '>=14'} @@ -7174,6 +7696,9 @@ packages: engines: {node: '>=12.0.0'} hasBin: true + walk-up-path@3.0.1: + resolution: {integrity: sha512-9YlCL/ynK3CTlrSRrDxZvUauLzAswPCrsaCgilqFevUYpeEW0/3ScEjaa3kbW/T0ghhkEr7mv+fpjqn1Y1YuTA==} + walker@1.0.8: resolution: {integrity: sha512-ts/8E8l5b7kY0vlWLewOkDXMmPdLcVV4GmOQLyxuSswIJsweeFZtAsMF7k1Nszz+TYBQrlYRmzOnr398y1JemQ==} @@ -7326,6 +7851,11 @@ packages: engines: {node: '>= 8'} hasBin: true + which@4.0.0: + resolution: {integrity: sha512-GlaYyEb07DPxYCKhKzplCWBJtvxZcZMrL+4UkrTSJHHPyZU4mYYTv3qaOe77H7EODLSSopAUFAc6W8U4yqvscg==} + engines: {node: ^16.13.0 || >=18.0.0} + hasBin: true + wildcard@2.0.1: resolution: {integrity: sha512-CC1bOL87PIWSBhDcTrdeLo6eGT7mCFtrg0uIJtqJUFyK+eJnzl8A1niH56uu7KMa5XFrtiV+AQuHO3n7DsHnLQ==} @@ -7460,6 +7990,9 @@ packages: zod@3.25.76: resolution: {integrity: sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ==} + zwitch@2.0.4: + resolution: {integrity: sha512-bXE4cR/kVZhKZX/RjPEflHaKVhUVl85noU3v6b8apfQEc1x4A+zBxjZ4lN8LqGd6WZ3dl98pY4o717VFmoPp+A==} + snapshots: '@ampproject/remapping@2.3.0': @@ -9344,6 +9877,58 @@ snapshots: '@nodelib/fs.scandir': 2.1.5 fastq: 1.19.1 + '@npmcli/config@8.3.4': + dependencies: + '@npmcli/map-workspaces': 3.0.6 + '@npmcli/package-json': 5.2.1 + ci-info: 4.3.1 + ini: 4.1.3 + nopt: 7.2.1 + proc-log: 4.2.0 + semver: 7.7.3 + walk-up-path: 3.0.1 + transitivePeerDependencies: + - bluebird + + '@npmcli/git@5.0.8': + dependencies: + '@npmcli/promise-spawn': 7.0.2 + ini: 4.1.3 + lru-cache: 10.4.3 + npm-pick-manifest: 9.1.0 + proc-log: 4.2.0 + promise-inflight: 1.0.1 + promise-retry: 2.0.1 + semver: 7.7.3 + which: 4.0.0 + transitivePeerDependencies: + - bluebird + + '@npmcli/map-workspaces@3.0.6': + dependencies: + '@npmcli/name-from-folder': 2.0.0 + glob: 10.4.5 + minimatch: 9.0.5 + read-package-json-fast: 3.0.2 + + '@npmcli/name-from-folder@2.0.0': {} + + '@npmcli/package-json@5.2.1': + dependencies: + '@npmcli/git': 5.0.8 + glob: 10.4.5 + hosted-git-info: 7.0.2 + json-parse-even-better-errors: 3.0.2 + normalize-package-data: 6.0.2 + proc-log: 4.2.0 + semver: 7.7.3 + transitivePeerDependencies: + - bluebird + + '@npmcli/promise-spawn@7.0.2': + dependencies: + which: 4.0.0 + '@opentelemetry/api-logs@0.57.2': dependencies: '@opentelemetry/api': 1.9.0 @@ -10064,6 +10649,10 @@ snapshots: '@types/node': 24.10.0 '@types/responselike': 1.0.3 + '@types/concat-stream@2.0.3': + dependencies: + '@types/node': 24.10.0 + '@types/connect-history-api-fallback@1.5.4': dependencies: '@types/express-serve-static-core': 4.19.7 @@ -10073,6 +10662,10 @@ snapshots: dependencies: '@types/node': 24.10.0 + '@types/debug@4.1.12': + dependencies: + '@types/ms': 2.1.0 + '@types/eslint-scope@3.7.7': dependencies: '@types/eslint': 9.6.1 @@ -10083,6 +10676,10 @@ snapshots: '@types/estree': 1.0.8 '@types/json-schema': 7.0.15 + '@types/estree-jsx@1.0.5': + dependencies: + '@types/estree': 1.0.8 + '@types/estree@1.0.8': {} '@types/express-serve-static-core@4.19.7': @@ -10103,6 +10700,10 @@ snapshots: dependencies: '@types/node': 24.10.0 + '@types/hast@3.0.4': + dependencies: + '@types/unist': 3.0.3 + '@types/http-cache-semantics@4.0.4': {} '@types/http-errors@2.0.5': {} @@ -10111,6 +10712,8 @@ snapshots: dependencies: '@types/node': 24.10.0 + '@types/is-empty@1.2.3': {} + '@types/istanbul-lib-coverage@2.0.6': {} '@types/istanbul-lib-report@3.0.3': @@ -10135,10 +10738,16 @@ snapshots: dependencies: '@types/node': 24.10.0 + '@types/mdast@4.0.4': + dependencies: + '@types/unist': 3.0.3 + '@types/mime@1.3.5': {} '@types/minimist@1.2.5': {} + '@types/ms@2.1.0': {} + '@types/mysql@2.15.26': dependencies: '@types/node': 24.10.0 @@ -10213,6 +10822,8 @@ snapshots: '@types/stack-utils@2.0.3': {} + '@types/supports-color@8.1.3': {} + '@types/tapable@1.0.12': optional: true @@ -10220,6 +10831,8 @@ snapshots: dependencies: '@types/node': 24.10.0 + '@types/text-table@0.2.5': {} + '@types/tough-cookie@4.0.5': {} '@types/uglify-js@3.17.5': @@ -10227,6 +10840,10 @@ snapshots: source-map: 0.6.1 optional: true + '@types/unist@2.0.11': {} + + '@types/unist@3.0.3': {} + '@types/webpack-sources@3.2.3': dependencies: '@types/node': 24.10.0 @@ -11112,6 +11729,8 @@ snapshots: abab@2.0.6: {} + abbrev@2.0.0: {} + accepts@1.3.8: dependencies: mime-types: 2.1.35 @@ -11452,6 +12071,8 @@ snapshots: babel-plugin-jest-hoist: 29.6.3 babel-preset-current-node-syntax: 1.2.0(@babel/core@7.25.7) + bail@2.0.2: {} + balanced-match@1.0.2: {} balanced-match@2.0.0: {} @@ -11656,6 +12277,8 @@ snapshots: tslib: 2.8.1 upper-case-first: 2.0.2 + ccount@2.0.1: {} + chalk@2.4.2: dependencies: ansi-styles: 3.2.1 @@ -11691,6 +12314,14 @@ snapshots: char-regex@1.0.2: {} + character-entities-html4@2.1.0: {} + + character-entities-legacy@3.0.0: {} + + character-entities@2.0.2: {} + + character-reference-invalid@2.0.1: {} + chardet@0.7.0: {} chardet@2.1.0: {} @@ -11760,6 +12391,8 @@ snapshots: ci-info@3.9.0: {} + ci-info@4.3.1: {} + cjs-module-lexer@1.4.3: {} cli-cursor@3.1.0: @@ -11800,6 +12433,8 @@ snapshots: co@4.6.0: {} + collapse-white-space@2.1.0: {} + collect-v8-coverage@1.0.3: {} color-convert@1.9.3: @@ -11822,6 +12457,8 @@ snapshots: dependencies: delayed-stream: 1.0.0 + comma-separated-tokens@2.0.3: {} + commander@10.0.1: {} commander@11.1.0: {} @@ -11863,6 +12500,13 @@ snapshots: readable-stream: 2.3.8 typedarray: 0.0.6 + concat-stream@2.0.0: + dependencies: + buffer-from: 1.1.2 + inherits: 2.0.4 + readable-stream: 3.6.2 + typedarray: 0.0.6 + configstore@7.0.0: dependencies: atomically: 2.0.3 @@ -12161,6 +12805,10 @@ snapshots: decimal.js@10.6.0: {} + decode-named-character-reference@1.2.0: + dependencies: + character-entities: 2.0.2 + decompress-response@6.0.0: dependencies: mimic-response: 3.1.0 @@ -12214,6 +12862,8 @@ snapshots: depd@2.0.0: {} + dequal@2.0.3: {} + destroy@1.2.0: {} detect-indent@6.1.0: {} @@ -12225,6 +12875,10 @@ snapshots: detect-node@2.1.0: {} + devlop@1.1.0: + dependencies: + dequal: 2.0.3 + devtools-protocol@0.0.1367902: {} devtools-protocol@0.0.1464554: {} @@ -12312,6 +12966,8 @@ snapshots: emittery@0.13.1: {} + emoji-regex@10.6.0: {} + emoji-regex@8.0.0: {} emoji-regex@9.2.2: {} @@ -12346,6 +13002,8 @@ snapshots: envinfo@7.20.0: {} + err-code@2.0.3: {} + error-ex@1.3.4: dependencies: is-arrayish: 0.2.1 @@ -12467,6 +13125,8 @@ snapshots: escape-string-regexp@4.0.0: {} + escape-string-regexp@5.0.0: {} + escodegen@2.1.0: dependencies: esprima: 4.0.1 @@ -12768,6 +13428,8 @@ snapshots: transitivePeerDependencies: - supports-color + extend@3.0.2: {} + extendable-error@0.1.7: {} external-editor@3.1.0: @@ -12821,6 +13483,10 @@ snapshots: dependencies: reusify: 1.1.0 + fault@2.0.1: + dependencies: + format: 0.2.2 + faye-websocket@0.11.4: dependencies: websocket-driver: 0.7.4 @@ -12949,6 +13615,8 @@ snapshots: hasown: 2.0.2 mime-types: 2.1.35 + format@0.2.2: {} + forwarded-parse@2.1.2: {} forwarded@0.2.0: {} @@ -13192,6 +13860,10 @@ snapshots: dependencies: lru-cache: 6.0.0 + hosted-git-info@7.0.2: + dependencies: + lru-cache: 10.4.3 + hpack.js@2.1.6: dependencies: inherits: 2.0.4 @@ -13318,6 +13990,8 @@ snapshots: ignore@5.3.2: {} + ignore@6.0.2: {} + ignore@7.0.5: {} image-ssim@0.2.0: {} @@ -13350,6 +14024,8 @@ snapshots: pkg-dir: 4.2.0 resolve-cwd: 3.0.0 + import-meta-resolve@4.2.0: {} + imurmurhash@0.1.4: {} indent-string@4.0.0: {} @@ -13367,6 +14043,8 @@ snapshots: ini@3.0.1: {} + ini@4.1.3: {} + inquirer@7.3.3: dependencies: ansi-escapes: 4.3.2 @@ -13413,6 +14091,13 @@ snapshots: irregular-plurals@3.5.0: {} + is-alphabetical@2.0.1: {} + + is-alphanumerical@2.0.1: + dependencies: + is-alphabetical: 2.0.1 + is-decimal: 2.0.1 + is-array-buffer@3.0.5: dependencies: call-bind: 1.0.8 @@ -13465,10 +14150,14 @@ snapshots: call-bound: 1.0.4 has-tostringtag: 1.0.2 + is-decimal@2.0.1: {} + is-docker@2.2.1: {} is-docker@3.0.0: {} + is-empty@1.2.0: {} + is-extendable@0.1.1: {} is-extglob@2.1.1: {} @@ -13492,6 +14181,8 @@ snapshots: dependencies: is-extglob: 2.1.1 + is-hexadecimal@2.0.1: {} + is-inside-container@1.0.0: dependencies: is-docker: 3.0.0 @@ -13517,6 +14208,8 @@ snapshots: is-plain-obj@3.0.0: {} + is-plain-obj@4.1.0: {} + is-plain-object@2.0.4: dependencies: isobject: 3.0.1 @@ -13590,6 +14283,8 @@ snapshots: isexe@2.0.0: {} + isexe@3.1.1: {} + isobject@3.0.1: {} istanbul-lib-coverage@3.2.2: {} @@ -14057,6 +14752,8 @@ snapshots: json-parse-even-better-errors@2.3.1: {} + json-parse-even-better-errors@3.0.2: {} + json-schema-traverse@0.4.1: {} json-schema-traverse@1.0.0: {} @@ -14233,10 +14930,19 @@ snapshots: lines-and-columns@1.2.4: {} + lines-and-columns@2.0.4: {} + linkify-it@3.0.3: dependencies: uc.micro: 1.0.6 + load-plugin@6.0.3: + dependencies: + '@npmcli/config': 8.3.4 + import-meta-resolve: 4.2.0 + transitivePeerDependencies: + - bluebird + loader-runner@4.3.0: {} loader-runner@4.3.1: {} @@ -14286,6 +14992,8 @@ snapshots: loglevel@1.9.2: {} + longest-streak@3.1.0: {} + lookup-closest-locale@6.2.0: {} loose-envify@1.4.0: @@ -14324,6 +15032,8 @@ snapshots: map-values@1.0.1: {} + markdown-extensions@2.0.0: {} + markdown-it@12.3.2: dependencies: argparse: 2.0.1 @@ -14332,6 +15042,8 @@ snapshots: mdurl: 1.0.1 uc.micro: 1.0.6 + markdown-table@3.0.4: {} + markdownlint-cli@0.31.1: dependencies: commander: 9.0.0 @@ -14357,6 +15069,151 @@ snapshots: mathml-tag-names@2.1.3: {} + mdast-comment-marker@3.0.0: + dependencies: + '@types/mdast': 4.0.4 + mdast-util-mdx-expression: 2.0.1 + transitivePeerDependencies: + - supports-color + + mdast-util-directive@3.1.0: + dependencies: + '@types/mdast': 4.0.4 + '@types/unist': 3.0.3 + ccount: 2.0.1 + devlop: 1.1.0 + mdast-util-from-markdown: 2.0.2 + mdast-util-to-markdown: 2.1.2 + parse-entities: 4.0.2 + stringify-entities: 4.0.4 + unist-util-visit-parents: 6.0.2 + transitivePeerDependencies: + - supports-color + + mdast-util-find-and-replace@3.0.2: + dependencies: + '@types/mdast': 4.0.4 + escape-string-regexp: 5.0.0 + unist-util-is: 6.0.1 + unist-util-visit-parents: 6.0.2 + + mdast-util-from-markdown@2.0.2: + dependencies: + '@types/mdast': 4.0.4 + '@types/unist': 3.0.3 + decode-named-character-reference: 1.2.0 + devlop: 1.1.0 + mdast-util-to-string: 4.0.0 + micromark: 4.0.2 + micromark-util-decode-numeric-character-reference: 2.0.2 + micromark-util-decode-string: 2.0.1 + micromark-util-normalize-identifier: 2.0.1 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.2 + unist-util-stringify-position: 4.0.0 + transitivePeerDependencies: + - supports-color + + mdast-util-frontmatter@2.0.1: + dependencies: + '@types/mdast': 4.0.4 + devlop: 1.1.0 + escape-string-regexp: 5.0.0 + mdast-util-from-markdown: 2.0.2 + mdast-util-to-markdown: 2.1.2 + micromark-extension-frontmatter: 2.0.0 + transitivePeerDependencies: + - supports-color + + mdast-util-gfm-autolink-literal@2.0.1: + dependencies: + '@types/mdast': 4.0.4 + ccount: 2.0.1 + devlop: 1.1.0 + mdast-util-find-and-replace: 3.0.2 + micromark-util-character: 2.1.1 + + mdast-util-gfm-footnote@2.1.0: + dependencies: + '@types/mdast': 4.0.4 + devlop: 1.1.0 + mdast-util-from-markdown: 2.0.2 + mdast-util-to-markdown: 2.1.2 + micromark-util-normalize-identifier: 2.0.1 + transitivePeerDependencies: + - supports-color + + mdast-util-gfm-strikethrough@2.0.0: + dependencies: + '@types/mdast': 4.0.4 + mdast-util-from-markdown: 2.0.2 + mdast-util-to-markdown: 2.1.2 + transitivePeerDependencies: + - supports-color + + mdast-util-gfm-table@2.0.0: + dependencies: + '@types/mdast': 4.0.4 + devlop: 1.1.0 + markdown-table: 3.0.4 + mdast-util-from-markdown: 2.0.2 + mdast-util-to-markdown: 2.1.2 + transitivePeerDependencies: + - supports-color + + mdast-util-gfm-task-list-item@2.0.0: + dependencies: + '@types/mdast': 4.0.4 + devlop: 1.1.0 + mdast-util-from-markdown: 2.0.2 + mdast-util-to-markdown: 2.1.2 + transitivePeerDependencies: + - supports-color + + mdast-util-gfm@3.1.0: + dependencies: + mdast-util-from-markdown: 2.0.2 + mdast-util-gfm-autolink-literal: 2.0.1 + mdast-util-gfm-footnote: 2.1.0 + mdast-util-gfm-strikethrough: 2.0.0 + mdast-util-gfm-table: 2.0.0 + mdast-util-gfm-task-list-item: 2.0.0 + mdast-util-to-markdown: 2.1.2 + transitivePeerDependencies: + - supports-color + + mdast-util-mdx-expression@2.0.1: + dependencies: + '@types/estree-jsx': 1.0.5 + '@types/hast': 3.0.4 + '@types/mdast': 4.0.4 + devlop: 1.1.0 + mdast-util-from-markdown: 2.0.2 + mdast-util-to-markdown: 2.1.2 + transitivePeerDependencies: + - supports-color + + mdast-util-phrasing@4.1.0: + dependencies: + '@types/mdast': 4.0.4 + unist-util-is: 6.0.1 + + mdast-util-to-markdown@2.1.2: + dependencies: + '@types/mdast': 4.0.4 + '@types/unist': 3.0.3 + longest-streak: 3.1.0 + mdast-util-phrasing: 4.1.0 + mdast-util-to-string: 4.0.0 + micromark-util-classify-character: 2.0.1 + micromark-util-decode-string: 2.0.1 + unist-util-visit: 5.0.0 + zwitch: 2.0.4 + + mdast-util-to-string@4.0.0: + dependencies: + '@types/mdast': 4.0.4 + mdn-data@2.0.28: {} mdn-data@2.0.30: {} @@ -14411,6 +15268,204 @@ snapshots: methods@1.1.2: {} + micromark-core-commonmark@2.0.3: + dependencies: + decode-named-character-reference: 1.2.0 + devlop: 1.1.0 + micromark-factory-destination: 2.0.1 + micromark-factory-label: 2.0.1 + micromark-factory-space: 2.0.1 + micromark-factory-title: 2.0.1 + micromark-factory-whitespace: 2.0.1 + micromark-util-character: 2.1.1 + micromark-util-chunked: 2.0.1 + micromark-util-classify-character: 2.0.1 + micromark-util-html-tag-name: 2.0.1 + micromark-util-normalize-identifier: 2.0.1 + micromark-util-resolve-all: 2.0.1 + micromark-util-subtokenize: 2.1.0 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.2 + + micromark-extension-frontmatter@2.0.0: + dependencies: + fault: 2.0.1 + micromark-util-character: 2.1.1 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.2 + + micromark-extension-gfm-autolink-literal@2.1.0: + dependencies: + micromark-util-character: 2.1.1 + micromark-util-sanitize-uri: 2.0.1 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.2 + + micromark-extension-gfm-footnote@2.1.0: + dependencies: + devlop: 1.1.0 + micromark-core-commonmark: 2.0.3 + micromark-factory-space: 2.0.1 + micromark-util-character: 2.1.1 + micromark-util-normalize-identifier: 2.0.1 + micromark-util-sanitize-uri: 2.0.1 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.2 + + micromark-extension-gfm-strikethrough@2.1.0: + dependencies: + devlop: 1.1.0 + micromark-util-chunked: 2.0.1 + micromark-util-classify-character: 2.0.1 + micromark-util-resolve-all: 2.0.1 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.2 + + micromark-extension-gfm-table@2.1.1: + dependencies: + devlop: 1.1.0 + micromark-factory-space: 2.0.1 + micromark-util-character: 2.1.1 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.2 + + micromark-extension-gfm-tagfilter@2.0.0: + dependencies: + micromark-util-types: 2.0.2 + + micromark-extension-gfm-task-list-item@2.1.0: + dependencies: + devlop: 1.1.0 + micromark-factory-space: 2.0.1 + micromark-util-character: 2.1.1 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.2 + + micromark-extension-gfm@3.0.0: + dependencies: + micromark-extension-gfm-autolink-literal: 2.1.0 + micromark-extension-gfm-footnote: 2.1.0 + micromark-extension-gfm-strikethrough: 2.1.0 + micromark-extension-gfm-table: 2.1.1 + micromark-extension-gfm-tagfilter: 2.0.0 + micromark-extension-gfm-task-list-item: 2.1.0 + micromark-util-combine-extensions: 2.0.1 + micromark-util-types: 2.0.2 + + micromark-factory-destination@2.0.1: + dependencies: + micromark-util-character: 2.1.1 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.2 + + micromark-factory-label@2.0.1: + dependencies: + devlop: 1.1.0 + micromark-util-character: 2.1.1 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.2 + + micromark-factory-space@2.0.1: + dependencies: + micromark-util-character: 2.1.1 + micromark-util-types: 2.0.2 + + micromark-factory-title@2.0.1: + dependencies: + micromark-factory-space: 2.0.1 + micromark-util-character: 2.1.1 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.2 + + micromark-factory-whitespace@2.0.1: + dependencies: + micromark-factory-space: 2.0.1 + micromark-util-character: 2.1.1 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.2 + + micromark-util-character@2.1.1: + dependencies: + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.2 + + micromark-util-chunked@2.0.1: + dependencies: + micromark-util-symbol: 2.0.1 + + micromark-util-classify-character@2.0.1: + dependencies: + micromark-util-character: 2.1.1 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.2 + + micromark-util-combine-extensions@2.0.1: + dependencies: + micromark-util-chunked: 2.0.1 + micromark-util-types: 2.0.2 + + micromark-util-decode-numeric-character-reference@2.0.2: + dependencies: + micromark-util-symbol: 2.0.1 + + micromark-util-decode-string@2.0.1: + dependencies: + decode-named-character-reference: 1.2.0 + micromark-util-character: 2.1.1 + micromark-util-decode-numeric-character-reference: 2.0.2 + micromark-util-symbol: 2.0.1 + + micromark-util-encode@2.0.1: {} + + micromark-util-html-tag-name@2.0.1: {} + + micromark-util-normalize-identifier@2.0.1: + dependencies: + micromark-util-symbol: 2.0.1 + + micromark-util-resolve-all@2.0.1: + dependencies: + micromark-util-types: 2.0.2 + + micromark-util-sanitize-uri@2.0.1: + dependencies: + micromark-util-character: 2.1.1 + micromark-util-encode: 2.0.1 + micromark-util-symbol: 2.0.1 + + micromark-util-subtokenize@2.1.0: + dependencies: + devlop: 1.1.0 + micromark-util-chunked: 2.0.1 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.2 + + micromark-util-symbol@2.0.1: {} + + micromark-util-types@2.0.2: {} + + micromark@4.0.2: + dependencies: + '@types/debug': 4.1.12 + debug: 4.4.3 + decode-named-character-reference: 1.2.0 + devlop: 1.1.0 + micromark-core-commonmark: 2.0.3 + micromark-factory-space: 2.0.1 + micromark-util-character: 2.1.1 + micromark-util-chunked: 2.0.1 + micromark-util-combine-extensions: 2.0.1 + micromark-util-decode-numeric-character-reference: 2.0.2 + micromark-util-encode: 2.0.1 + micromark-util-normalize-identifier: 2.0.1 + micromark-util-resolve-all: 2.0.1 + micromark-util-sanitize-uri: 2.0.1 + micromark-util-subtokenize: 2.1.0 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.2 + transitivePeerDependencies: + - supports-color + micromatch@4.0.8: dependencies: braces: 3.0.3 @@ -14542,6 +15597,10 @@ snapshots: node-releases@2.0.27: {} + nopt@7.2.1: + dependencies: + abbrev: 2.0.0 + normalize-package-data@2.5.0: dependencies: hosted-git-info: 2.8.9 @@ -14556,6 +15615,12 @@ snapshots: semver: 7.7.2 validate-npm-package-license: 3.0.4 + normalize-package-data@6.0.2: + dependencies: + hosted-git-info: 7.0.2 + semver: 7.7.3 + validate-npm-package-license: 3.0.4 + normalize-path@3.0.0: {} normalize-range@0.1.2: {} @@ -14566,8 +15631,21 @@ snapshots: dependencies: npm-normalize-package-bin: 1.0.1 + npm-install-checks@6.3.0: + dependencies: + semver: 7.7.3 + npm-normalize-package-bin@1.0.1: {} + npm-normalize-package-bin@3.0.1: {} + + npm-package-arg@11.0.3: + dependencies: + hosted-git-info: 7.0.2 + proc-log: 4.2.0 + semver: 7.7.3 + validate-npm-package-name: 5.0.1 + npm-package-json-lint@6.4.0(typescript@5.8.3): dependencies: ajv: 6.12.6 @@ -14598,6 +15676,13 @@ snapshots: npm-bundled: 1.1.2 npm-normalize-package-bin: 1.0.1 + npm-pick-manifest@9.1.0: + dependencies: + npm-install-checks: 6.3.0 + npm-normalize-package-bin: 3.0.1 + npm-package-arg: 11.0.3 + semver: 7.7.3 + npm-run-path@4.0.1: dependencies: path-key: 3.1.1 @@ -14788,6 +15873,16 @@ snapshots: parse-cache-control@1.0.1: {} + parse-entities@4.0.2: + dependencies: + '@types/unist': 2.0.11 + character-entities-legacy: 3.0.0 + character-reference-invalid: 2.0.1 + decode-named-character-reference: 1.2.0 + is-alphanumerical: 2.0.1 + is-decimal: 2.0.1 + is-hexadecimal: 2.0.1 + parse-json@5.2.0: dependencies: '@babel/code-frame': 7.27.1 @@ -14795,6 +15890,14 @@ snapshots: json-parse-even-better-errors: 2.3.1 lines-and-columns: 1.2.4 + parse-json@7.1.1: + dependencies: + '@babel/code-frame': 7.27.1 + error-ex: 1.3.4 + json-parse-even-better-errors: 3.0.2 + lines-and-columns: 2.0.4 + type-fest: 3.13.1 + parse-passwd@1.0.0: {} parse5@7.3.0: @@ -14876,6 +15979,8 @@ snapshots: dependencies: irregular-plurals: 3.5.0 + pluralize@8.0.0: {} + possible-typed-array-names@1.1.0: {} postcss-calc@9.0.1(postcss@8.5.6): @@ -15123,10 +16228,19 @@ snapshots: ansi-styles: 5.2.0 react-is: 18.3.1 + proc-log@4.2.0: {} + process-nextick-args@2.0.1: {} progress@2.0.3: {} + promise-inflight@1.0.1: {} + + promise-retry@2.0.1: + dependencies: + err-code: 2.0.3 + retry: 0.12.0 + prompts@2.4.2: dependencies: kleur: 3.0.3 @@ -15268,6 +16382,11 @@ snapshots: dependencies: pify: 2.3.0 + read-package-json-fast@3.0.2: + dependencies: + json-parse-even-better-errors: 3.0.2 + npm-normalize-package-bin: 3.0.1 + read-pkg-up@7.0.1: dependencies: find-up: 4.1.0 @@ -15375,6 +16494,208 @@ snapshots: dependencies: jsesc: 3.1.0 + remark-cli@12.0.1: + dependencies: + import-meta-resolve: 4.2.0 + markdown-extensions: 2.0.0 + remark: 15.0.1 + unified-args: 11.0.1 + transitivePeerDependencies: + - bluebird + - supports-color + + remark-frontmatter@5.0.0: + dependencies: + '@types/mdast': 4.0.4 + mdast-util-frontmatter: 2.0.1 + micromark-extension-frontmatter: 2.0.0 + unified: 11.0.5 + transitivePeerDependencies: + - supports-color + + remark-gfm@4.0.1: + dependencies: + '@types/mdast': 4.0.4 + mdast-util-gfm: 3.1.0 + micromark-extension-gfm: 3.0.0 + remark-parse: 11.0.0 + remark-stringify: 11.0.0 + unified: 11.0.5 + transitivePeerDependencies: + - supports-color + + remark-lint-final-newline@3.0.1: + dependencies: + '@types/mdast': 4.0.4 + devlop: 1.1.0 + unified-lint-rule: 3.0.1 + vfile-location: 5.0.3 + + remark-lint-hard-break-spaces@4.1.1: + dependencies: + '@types/mdast': 4.0.4 + unified-lint-rule: 3.0.1 + unist-util-position: 5.0.0 + unist-util-visit: 5.0.0 + + remark-lint-list-item-bullet-indent@5.0.1: + dependencies: + '@types/mdast': 4.0.4 + pluralize: 8.0.0 + unified-lint-rule: 3.0.1 + unist-util-position: 5.0.0 + + remark-lint-list-item-indent@4.0.1: + dependencies: + '@types/mdast': 4.0.4 + mdast-util-phrasing: 4.1.0 + pluralize: 8.0.0 + unified-lint-rule: 3.0.1 + unist-util-position: 5.0.0 + unist-util-visit-parents: 6.0.2 + + remark-lint-no-blockquote-without-marker@6.0.1: + dependencies: + '@types/mdast': 4.0.4 + devlop: 1.1.0 + mdast-util-directive: 3.1.0 + mdast-util-phrasing: 4.1.0 + pluralize: 8.0.0 + unified-lint-rule: 3.0.1 + unist-util-position: 5.0.0 + unist-util-visit-parents: 6.0.2 + vfile-location: 5.0.3 + transitivePeerDependencies: + - supports-color + + remark-lint-no-duplicate-definitions@4.0.1: + dependencies: + '@types/mdast': 4.0.4 + devlop: 1.1.0 + mdast-util-phrasing: 4.1.0 + unified-lint-rule: 3.0.1 + unist-util-visit-parents: 6.0.2 + vfile-message: 4.0.3 + + remark-lint-no-heading-content-indent@5.0.1: + dependencies: + '@types/mdast': 4.0.4 + mdast-util-phrasing: 4.1.0 + pluralize: 8.0.0 + unified-lint-rule: 3.0.1 + unist-util-position: 5.0.0 + unist-util-visit-parents: 6.0.2 + + remark-lint-no-literal-urls@4.0.1: + dependencies: + '@types/mdast': 4.0.4 + mdast-util-to-string: 4.0.0 + micromark-util-character: 2.1.1 + unified-lint-rule: 3.0.1 + unist-util-position: 5.0.0 + unist-util-visit-parents: 6.0.2 + + remark-lint-no-shortcut-reference-image@4.0.1: + dependencies: + '@types/mdast': 4.0.4 + unified-lint-rule: 3.0.1 + unist-util-visit-parents: 6.0.2 + + remark-lint-no-shortcut-reference-link@4.0.1: + dependencies: + '@types/mdast': 4.0.4 + unified-lint-rule: 3.0.1 + unist-util-visit-parents: 6.0.2 + + remark-lint-no-undefined-references@5.0.2: + dependencies: + '@types/mdast': 4.0.4 + collapse-white-space: 2.1.0 + devlop: 1.1.0 + micromark-util-normalize-identifier: 2.0.1 + unified-lint-rule: 3.0.1 + unist-util-position: 5.0.0 + unist-util-visit-parents: 6.0.2 + vfile-location: 5.0.3 + + remark-lint-no-unused-definitions@4.0.2: + dependencies: + '@types/mdast': 4.0.4 + devlop: 1.1.0 + unified-lint-rule: 3.0.1 + unist-util-visit-parents: 6.0.2 + + remark-lint-ordered-list-marker-style@4.0.1: + dependencies: + '@types/mdast': 4.0.4 + mdast-util-phrasing: 4.1.0 + micromark-util-character: 2.1.1 + unified-lint-rule: 3.0.1 + unist-util-position: 5.0.0 + unist-util-visit-parents: 6.0.2 + vfile-message: 4.0.3 + + remark-lint@10.0.1: + dependencies: + '@types/mdast': 4.0.4 + remark-message-control: 8.0.0 + unified: 11.0.5 + transitivePeerDependencies: + - supports-color + + remark-message-control@8.0.0: + dependencies: + '@types/mdast': 4.0.4 + mdast-comment-marker: 3.0.0 + unified-message-control: 5.0.0 + vfile: 6.0.3 + transitivePeerDependencies: + - supports-color + + remark-parse@11.0.0: + dependencies: + '@types/mdast': 4.0.4 + mdast-util-from-markdown: 2.0.2 + micromark-util-types: 2.0.2 + unified: 11.0.5 + transitivePeerDependencies: + - supports-color + + remark-preset-lint-recommended@7.0.1: + dependencies: + remark-lint: 10.0.1 + remark-lint-final-newline: 3.0.1 + remark-lint-hard-break-spaces: 4.1.1 + remark-lint-list-item-bullet-indent: 5.0.1 + remark-lint-list-item-indent: 4.0.1 + remark-lint-no-blockquote-without-marker: 6.0.1 + remark-lint-no-duplicate-definitions: 4.0.1 + remark-lint-no-heading-content-indent: 5.0.1 + remark-lint-no-literal-urls: 4.0.1 + remark-lint-no-shortcut-reference-image: 4.0.1 + remark-lint-no-shortcut-reference-link: 4.0.1 + remark-lint-no-undefined-references: 5.0.2 + remark-lint-no-unused-definitions: 4.0.2 + remark-lint-ordered-list-marker-style: 4.0.1 + unified: 11.0.5 + transitivePeerDependencies: + - supports-color + + remark-stringify@11.0.0: + dependencies: + '@types/mdast': 4.0.4 + mdast-util-to-markdown: 2.1.2 + unified: 11.0.5 + + remark@15.0.1: + dependencies: + '@types/mdast': 4.0.4 + remark-parse: 11.0.0 + remark-stringify: 11.0.0 + unified: 11.0.5 + transitivePeerDependencies: + - supports-color + require-directory@2.1.1: {} require-from-string@2.0.2: {} @@ -15439,6 +16760,8 @@ snapshots: onetime: 5.1.2 signal-exit: 3.0.7 + retry@0.12.0: {} + retry@0.13.1: {} reusify@1.1.0: {} @@ -15797,6 +17120,8 @@ snapshots: source-map@0.7.6: {} + space-separated-tokens@2.0.2: {} + spawnd@10.1.4: dependencies: signal-exit: 4.1.0 @@ -15896,6 +17221,12 @@ snapshots: emoji-regex: 9.2.2 strip-ansi: 7.1.0 + string-width@6.1.0: + dependencies: + eastasianwidth: 0.2.0 + emoji-regex: 10.6.0 + strip-ansi: 7.1.0 + string.prototype.includes@2.0.1: dependencies: call-bind: 1.0.8 @@ -15954,6 +17285,11 @@ snapshots: dependencies: safe-buffer: 5.2.1 + stringify-entities@4.0.4: + dependencies: + character-entities-html4: 2.1.0 + character-entities-legacy: 3.0.0 + strip-ansi@6.0.1: dependencies: ansi-regex: 5.0.1 @@ -16144,6 +17480,8 @@ snapshots: dependencies: has-flag: 4.0.0 + supports-color@9.4.0: {} + supports-hyperlinks@2.3.0: dependencies: has-flag: 4.0.0 @@ -16314,6 +17652,8 @@ snapshots: dependencies: escape-string-regexp: 1.0.5 + trough@2.2.0: {} + ts-api-utils@1.4.3(typescript@5.8.3): dependencies: typescript: 5.8.3 @@ -16427,6 +17767,103 @@ snapshots: unicode-property-aliases-ecmascript@2.2.0: {} + unified-args@11.0.1: + dependencies: + '@types/text-table': 0.2.5 + chalk: 5.4.1 + chokidar: 3.6.0 + comma-separated-tokens: 2.0.3 + json5: 2.2.3 + minimist: 1.2.8 + strip-ansi: 7.1.0 + text-table: 0.2.0 + unified-engine: 11.2.2 + transitivePeerDependencies: + - bluebird + - supports-color + + unified-engine@11.2.2: + dependencies: + '@types/concat-stream': 2.0.3 + '@types/debug': 4.1.12 + '@types/is-empty': 1.2.3 + '@types/node': 22.15.17 + '@types/unist': 3.0.3 + concat-stream: 2.0.0 + debug: 4.4.3 + extend: 3.0.2 + glob: 10.4.5 + ignore: 6.0.2 + is-empty: 1.2.0 + is-plain-obj: 4.1.0 + load-plugin: 6.0.3 + parse-json: 7.1.1 + trough: 2.2.0 + unist-util-inspect: 8.1.0 + vfile: 6.0.3 + vfile-message: 4.0.3 + vfile-reporter: 8.1.1 + vfile-statistics: 3.0.0 + yaml: 2.8.1 + transitivePeerDependencies: + - bluebird + - supports-color + + unified-lint-rule@3.0.1: + dependencies: + '@types/unist': 3.0.3 + trough: 2.2.0 + unified: 11.0.5 + vfile: 6.0.3 + + unified-message-control@5.0.0: + dependencies: + '@types/unist': 3.0.3 + devlop: 1.1.0 + space-separated-tokens: 2.0.2 + unist-util-is: 6.0.1 + unist-util-visit: 5.0.0 + vfile: 6.0.3 + vfile-location: 5.0.3 + vfile-message: 4.0.3 + + unified@11.0.5: + dependencies: + '@types/unist': 3.0.3 + bail: 2.0.2 + devlop: 1.1.0 + extend: 3.0.2 + is-plain-obj: 4.1.0 + trough: 2.2.0 + vfile: 6.0.3 + + unist-util-inspect@8.1.0: + dependencies: + '@types/unist': 3.0.3 + + unist-util-is@6.0.1: + dependencies: + '@types/unist': 3.0.3 + + unist-util-position@5.0.0: + dependencies: + '@types/unist': 3.0.3 + + unist-util-stringify-position@4.0.0: + dependencies: + '@types/unist': 3.0.3 + + unist-util-visit-parents@6.0.2: + dependencies: + '@types/unist': 3.0.3 + unist-util-is: 6.0.1 + + unist-util-visit@5.0.0: + dependencies: + '@types/unist': 3.0.3 + unist-util-is: 6.0.1 + unist-util-visit-parents: 6.0.2 + universalify@0.1.2: {} universalify@0.2.0: {} @@ -16497,6 +17934,42 @@ snapshots: vary@1.1.2: {} + vfile-location@5.0.3: + dependencies: + '@types/unist': 3.0.3 + vfile: 6.0.3 + + vfile-message@4.0.3: + dependencies: + '@types/unist': 3.0.3 + unist-util-stringify-position: 4.0.0 + + vfile-reporter@8.1.1: + dependencies: + '@types/supports-color': 8.1.3 + string-width: 6.1.0 + supports-color: 9.4.0 + unist-util-stringify-position: 4.0.0 + vfile: 6.0.3 + vfile-message: 4.0.3 + vfile-sort: 4.0.0 + vfile-statistics: 3.0.0 + + vfile-sort@4.0.0: + dependencies: + vfile: 6.0.3 + vfile-message: 4.0.3 + + vfile-statistics@3.0.0: + dependencies: + vfile: 6.0.3 + vfile-message: 4.0.3 + + vfile@6.0.3: + dependencies: + '@types/unist': 3.0.3 + vfile-message: 4.0.3 + w3c-xmlserializer@4.0.0: dependencies: xml-name-validator: 4.0.0 @@ -16511,6 +17984,8 @@ snapshots: transitivePeerDependencies: - debug + walk-up-path@3.0.1: {} + walker@1.0.8: dependencies: makeerror: 1.0.12 @@ -16847,6 +18322,10 @@ snapshots: dependencies: isexe: 2.0.0 + which@4.0.0: + dependencies: + isexe: 3.1.1 + wildcard@2.0.1: {} word-wrap@1.2.5: {} @@ -16939,3 +18418,5 @@ snapshots: zod@3.23.8: {} zod@3.25.76: {} + + zwitch@2.0.4: {}